emud/area_current/
emud/area_current/castle/
emud/area_current/newareas/
emud/area_current/nwcentral/
emud/area_current/scontinent/
emud/clans/
emud/player/
emud/player/d/e/bak/
emud/player/e/m/
emud/player/e/m/bak/
/***************************************************************************
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills and Dug Michael.                               *
 *                                                                         *
 * Merc  2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael      *
 * Chastain, Michael Quan, and Mitchell Tse.                               *
 *                                                                         *
 * Original Diku Mud copyright (C) 1990 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/

#include "emud.h"

/*
	Local functions.
*/

void		say_spell			args( ( CHAR_DATA *ch, int sn ) );
int		multi_spell_level	args( ( CHAR_DATA *ch, int sn ) );
int		can_cast_spell		args( ( CHAR_DATA *ch, int sn ) );

int		caster_levels		args( ( CHAR_DATA *ch ) );
bool		is_safe_magic		args( ( CHAR_DATA *ch, CHAR_DATA *victim, int sn ) );
int		magic_modify		args( ( CHAR_DATA *ch, CHAR_DATA *victim, int sn, int level ) );
bool		can_mass_cast		args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );

#define DO_SPELL(spell) void spell( int sn, int level, CHAR_DATA *ch, void *vo, int target )

int value;	/* This is the value after the target */

void make_char_fight_char( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("make_char_fight_char(%p,%p)",ch,victim);

	if (ch == NULL || victim == NULL || victim->position == POS_DEAD)
	{
		pop_call();
		return;
	}

	if (ch == victim)
	{
		pop_call();
		return;
	}

	/*
		set recently fought
	*/

	if (!IS_NPC(ch) && IS_NPC(victim))
	{
		if (ch->leader && !IS_NPC(ch->leader))
		{
			victim->npcdata->pvnum_last_hit = ch->leader->pcdata->pvnum;
		}
		else
		{
			victim->npcdata->pvnum_last_hit = ch->pcdata->pvnum;
		}
	}
	pop_call();
	return;
}

/*
	Lookup a skill by name.
*/

int skill_lookup( char *name )
{
	int sn;

	push_call("skill_lookup(%p)",name);

	for (sn = 0 ; sn < MAX_SKILL ; sn++)
	{
		if (tolower(name[0]) == skill_table[sn].name[0])
		{
			if (!strcmp(name, skill_table[sn].name))
			{
				pop_call();
				return sn;
			}
		}
	}

	for (sn = 0 ; sn < MAX_SKILL ; sn++)
	{
		if (tolower(name[0]) == skill_table[sn].name[0])
		{
			if (is_multi_name_short(name, skill_table[sn].name))
			{
				pop_call();
				return sn;
			}
		}
	}

	pop_call();
	return -1;
}

/*
	Lookup a skill by slot number.
	Used for object loading.
*/

int slot_lookup( int slot )
{
	int sn;

	push_call("slot_lookup(%p)",slot);

	if (slot <= 0)
	{
		pop_call();
		return 0;
	}

	for (sn = 0 ; sn < MAX_SKILL ; sn++ )
	{
		if (slot == skill_table[sn].slot)
		{
			pop_call();
			return sn;
		}
	}

	bug("slot_lookup: bad slot %d.", slot);

	if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
	{
		abort();
	}

	pop_call();
	return -1;
}

/*
	Utter mystical words for an sn.
*/

void say_spell( CHAR_DATA *ch, int sn )
{
	char buf  [MAX_STRING_LENGTH];
	char buf2 [MAX_STRING_LENGTH];
	CHAR_DATA *rch;
	char *pName;
	int iSyl;
	int length;

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

	static const struct syl_type syl_table[] =
	{
		{ " ",      " "		},
		{ "ar",     "abra"		},
		{ "au",     "kada"		},
		{ "bless",  "fido"		},
		{ "blind",  "nose"		},
		{ "bur",    "mosa"		},
		{ "cu",     "judi"		},
		{ "de",     "oculo"		},
		{ "en",     "unso"		},
		{ "hance",  "sch"		},
		{ "light",  "dies"		},
		{ "lo",     "hi"		},
		{ "mor",    "zak"		},
		{ "move",   "sido"		},
		{ "ob",     "kn"		},
		{ "ness",   "lacri"		},
		{ "ning",   "illa"		},
		{ "per",    "duda"		},
		{ "ra",     "gru"		},
		{ "re",     "candus"	},
		{ "son",    "sabru"		},
		{ "tect",   "infra"		},
		{ "tri",    "cula"		},
		{ "ven",    "nofo"		},
		{ "a", "a" }, { "b", "b" }, { "c", "q" }, { "d", "e" },
		{ "e", "z" }, { "f", "y" }, { "g", "o" }, { "h", "p" },
		{ "i", "u" }, { "j", "y" }, { "k", "t" }, { "l", "r" },
		{ "m", "w" }, { "n", "i" }, { "o", "a" }, { "p", "s" },
		{ "q", "d" }, { "r", "f" }, { "s", "g" }, { "t", "h" },
		{ "u", "j" }, { "v", "z" }, { "w", "x" }, { "x", "n" },
		{ "y", "l" }, { "z", "k" }, {  "", ""  }
	};

	push_call("say_spell(%p,%p)",ch,sn);

	buf[0]	= '\0';

	for (pName = skill_table[sn].name ; *pName != '\0' ; pName += length)
	{
		for (iSyl = 0 ; (length = strlen(syl_table[iSyl].old)) != 0 ; iSyl++)
		{
			if (!str_prefix(syl_table[iSyl].old, pName))
			{
				strcat(buf, syl_table[iSyl].new);
				break;
			}
		}

		if ( length == 0 )
		{
			length = 1;
		}
	}

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

	/*
	   make wizcloaked gods even more invis,
	   their uttering cannot be heard...
	*/

	if (!IS_NPC(ch) && IS_SET(ch->act, PLR_WIZCLOAK))
	{
		pop_call();
		return;
	}

	for (rch = ch->in_room->first_person ; rch ; rch = rch->next_in_room)
	{
		if (rch != ch)
		{
			if (IS_NPC(rch) || !IS_SET(rch->pcdata->spam, 4096))
			{
				if (IS_NPC(rch) || learned(rch, sn) == 0
				|| (IS_AFFECTED(ch, AFF2_QUICKEN) && !IS_AFFECTED(rch, AFF2_QUICKEN))
				|| (skill_table[sn].follower && which_god(ch) != which_god(rch))
				|| (skill_table[sn].race && ch->race != rch->race))
				{
					act(buf2, ch, NULL, rch, TO_VICT);
				}
				else
				{
					act(buf,  ch, NULL, rch, TO_VICT);
				}
			}
		}
	}

	pop_call();
	return;
}

/*
	Compute a saving throw.
	Negative apply's make saving throw better.
*/

bool saves_spell( int level, CHAR_DATA *ch, CHAR_DATA *victim )
{
	CHAR_DATA *fch;
	int range, point;

	push_call("saves_spell(%p,%p,%p)",level,ch,victim);

	point = 50 + level * 3 / 4;

	if (IS_NPC(victim))
	{
		range = 100 + victim->level / 2 - GET_SAVING_THROW(victim) * 2;
	}
	else
	{
		range = 100 - GET_SAVING_THROW(victim) * 4;
	}

	/* Add a bit of distraction to tanking spell casters - Chaos 7/11/96  */

	for (fch = ch->in_room->first_person ; fch != NULL ; fch = fch->next_in_room)
	{
		if (fch != ch && fch->fighting != NULL && fch->fighting->who == ch)
		{
			range += fch->level/5;
		}
	}

	range -= get_curr_int(ch);

	if (IS_AFFECTED(victim, AFF_PROTECT_EVIL) && IS_EVIL(ch))
	{
		range += 15;
	}

	if (IS_AFFECTED(victim, AFF_PROTECT_GOOD) && IS_GOOD(ch))
	{
		range += 15;
	}

	if (range > 1 && number_range(1, range) >= point)
	{
		pop_call();
		return(TRUE);    /* Spell Fails */
	}
	else
	{
		pop_call();
		return( FALSE );   /* Spell Works */
	}
	/*  Chaos changing to universal scaling system  12/16/94 */
}

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

char *target_name;

void do_cast( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char arg3[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *obj;
	void *vo;
	int mana, sn, level, percentage, target;

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

	if (strlen(argument) > 100)
	{
		*(argument+80)='\0';
	}

	percentage = 100;

	argument = one_argument(argument, arg1);

	/*
		Grab reduced spell strength percentage value - Chaos 7/26/96
	*/

	if (*arg1 != '\0' && is_number(arg1))
	{
		percentage = atol(arg1);

		argument = one_argument(argument, arg1);

		percentage = URANGE(1, percentage, 100);
	}

	target_name = argument;
	argument    = one_argument( argument, arg2 );
	argument    = one_argument( argument, arg3 );

	if (strlen(target_name) > 50)
	{
		target_name[50] = '\0';
	}

	if (arg1[0] == '\0')
	{
		send_to_char( "Cast which what where?\n\r", ch );
		pop_call();
		return;
	}

	value = -1;   /* Default value */

	if (is_number(arg2))   /*  Special numbers only spell */
	{
		value = atol(arg2);
		strcpy( arg2, "");
		if (value < 1)
		{
			value = -1;   /* Default value */
		}
	}
	else if (arg3[0] != '\0')     /* Read the extra value  - Chaos  2/8/95  */
	{
		value = atol( arg3 );
		if ( value < 1 )
		{
			value = -1;   /* Default value */
		}
	}

	sn = skill_lookup( arg1 );

	if (sn < 0 || !is_spell(sn))
	{
		if (!IS_NPC(ch) && ch->desc == NULL)
		{
			log_printf("[%u] casting unknown spell: %s", ch->pIndexData->vnum, arg1);
		}
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}

	if ((level = can_cast_spell(ch, sn)) == -1)
	{
		pop_call();
		return;
	}

	if (is_safe_magic(ch, NULL, sn))
	{
		pop_call();
		return;
	}

	mana  = get_mana(ch, sn);

	level = level * percentage / 100 ;

	if (level < 1)
	{
		level = 1;
	}

	/*
		Locate targets.
	*/

	victim	= NULL;
	obj		= NULL;
	vo		= NULL;
	target	= skill_table[sn].target;

	switch (target)
	{
		default:
			bug( "do_cast: bad target for sn %d.", sn );
			pop_call();
			return;

		case TAR_IGNORE:
			break;

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

		case TAR_CHAR_DEFENSIVE:

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

			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}

			vo = (void *) victim;
			break;

		case TAR_CHAR_SELF:

			if (arg2[0] != '\0' && !is_name_short(arg2, ch->name))
			{
				send_to_char( "You cannot cast this spell on another.\n\r", ch );
				pop_call();
				return;
			}
			vo = (void *) ch;
			break;

		case TAR_OBJ_INV:

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

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

		case TAR_OBJ_CHAR_DEF:

			if (arg2[0] == '\0')
			{
				victim = ch;
			}
			else	if ((victim = get_char_room(ch, arg2)) == NULL)
			{
				if ((obj = get_obj_carry(ch, arg2)) == NULL)
				{
					send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
					pop_call();
					return;
				}
			}

			if (victim)
			{
				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_DEFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;

		case TAR_OBJ_CHAR_OFF:

			if (arg2[0] == '\0')
			{
				if (who_fighting(ch) == NULL)
				{
					send_to_char("Cast the spell on whom?\n\r", ch);
					pop_call();
					return;
				}
				victim = ch->fighting->who;
			}
			else	if ((victim = get_char_room(ch, arg2)) == NULL)
			{
				if ((obj = get_obj_carry(ch, arg2)) == NULL)
				{
					send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
					pop_call();
					return;
				}
			}

			if (victim)
			{
				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_OFFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;
	}

	if (!IS_IMMORTAL(ch) && ch->mana < mana)
	{
		send_to_char( "You don't have enough mana.\n\r", ch );
		pop_call();
		return;
	}

	if (strcasecmp( skill_table[sn].name, "ventriloquate" ) )
	{
		say_spell( ch, sn );
	}

	if (IS_AFFECTED(ch, AFF2_QUICKEN))
	{
		wait_state( ch, skill_table[sn].beats * 4 / 5 );
	}
	else
	{
		wait_state( ch, skill_table[sn].beats );
	}

	if (!IS_IMMORTAL(ch) && number_percent() > learned(ch, sn))
	{
		if (ch->fighting != NULL)
		{
			switch (number_bits(3))
			{
				case 0 : send_to_char( "This round of battle is too hectic to concentrate properly.\n\r",     ch ); break;
				case 1 : send_to_char( "There wasn't enough time this round to complete the casting.\n\r",    ch ); break;
				case 2 : send_to_char( "Despite your efforts you only produce worthless smoke.\n\r",          ch ); break;
				case 3 : send_to_char( "You lose control over your magic and only scorch the ground.\n\r",    ch ); break;
				case 4 : send_to_char( "The air sizzles with magic, but you fail to strike your victim.\n\r", ch ); break;
				case 5 : send_to_char( "You hesitate mid-way through the casting and nothing happens.\n\r",   ch ); break;
				default: send_to_char( "You lost your concentration.\n\r",                                    ch ); break;
			}
		}
		else
		{
			switch (number_bits(3))
			{
				case 0 : send_to_char( "A tickle in your nose prevents you from keeping your concentration.\n\r",    ch ); break;
				case 1 : send_to_char( "An itch on your leg keeps you from properly casting your spell.\n\r",        ch ); break;
				case 2 : send_to_char( "Something in your throat prevents you from uttering the proper phrase.\n\r", ch ); break;
				case 3 : send_to_char( "A twitch in your eye disrupts your concentration for a moment.\n\r",         ch ); break;
				case 4 : send_to_char( "You get a mental block mid-way through the casting.\n\r",                    ch ); break;
				default: send_to_char( "You lost your concentration.\n\r",                                           ch ); break;
			}
		}
		ch->mana -= mana / 2;
	}
	else
	{
		if (!IS_IMMORTAL(ch))
		{
			ch->mana -= mana;
		}

		if (number_bits(1) == 0 && is_affected(ch, gsn_mana_shackles))
		{
			switch (number_bits(2))
			{
				case 0:
					act("Your magical shackles send searing lightning through you as you cast.", ch, NULL, NULL, TO_CHAR);
					act("$n's magical shackles send searing lightning through $m as $e casts.",  ch, NULL, NULL, TO_ROOM);
					break;
				case 1:
					act("You reel in shock as your magical shackles claw into you as you cast.", ch, NULL, NULL, TO_CHAR);
					act("$n reels in shock as $s magical shackles claw into $m as $e casts.",    ch, NULL, NULL, TO_ROOM);
					break;
				case 2:
					act("Your magical shackles shock you to the core as you cast.", ch, NULL, NULL, TO_CHAR);
					act("$n's magical shackles shock $m to the core as $e casts.",  ch, NULL, NULL, TO_ROOM);
					break;
				case 3:
					act("You scream out in agony as your magical shackles shock you as you cast.", ch, NULL, NULL, TO_CHAR);
					act("$n screams out in agony as $s magical shackles shock $m as $e casts.",    ch, NULL, NULL, TO_ROOM);
					break;
			}
			ch->hit -= number_range(mana*3, mana*6);
		}

		if (victim && victim != ch && !IS_NPC(victim) && target == TAR_CHAR_OFFENSIVE)
		{
			if (IS_AWAKE(victim) && number_percent() < learned(victim, gsn_lightning_reflexes) / 4)
			{
				switch (number_bits(2))
				{
					case 0:
						act("You dive away from $n's $t with a lightning fast reflex.", ch, skill_table[sn].noun_damage, victim, TO_VICT);
						act("$N dives away from your $t with a lightning fast reflex.", ch, skill_table[sn].noun_damage, victim, TO_CHAR);
						break;
					case 1:
						act("You avoid $n's $t with a lightning fast side step.", ch, skill_table[sn].noun_damage, victim, TO_VICT);
						act("$N avoids your $t with a lightning fast side step.", ch, skill_table[sn].noun_damage, victim, TO_CHAR);
						break;
					case 2:
						act("You throw your body aside escaping from $n's $t.", ch, skill_table[sn].noun_damage, victim, TO_VICT);
						act("$N throws $S body aside escaping from your $t.",   ch, skill_table[sn].noun_damage, victim, TO_CHAR);
						break;
					case 3:
						act("You deftly move aside watching $n's $t go past.", ch, skill_table[sn].noun_damage, victim, TO_VICT);
						act("$N deftly moves aside watching your $t go past.", ch, skill_table[sn].noun_damage, victim, TO_CHAR);
						break;
				}
				check_improve(victim, gsn_lightning_reflexes);
				pop_call();
				return;
			}
		}

		if (victim && victim != ch && number_range(0, 4) == 0)
		{
			if (is_affected(victim, gsn_magic_mirror))
			{
				act("White lightning surrounds you, reflecting $n's magic.", ch, NULL, victim, TO_VICT    );
				act("White lightning surrounds $N, reflecting your magic.",  ch, NULL, victim, TO_CHAR    );
				act("White lightning surrounds $N, reflecting $n's magic.",  ch, NULL, victim, TO_NOTVICT );
				vo = (void *) ch;
				ch = victim;
			}
		}

		level = magic_modify(ch, victim, sn, level);

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

		check_improve(ch, sn);
	}

	if (target == TAR_CHAR_OFFENSIVE)
	{
		if (victim != ch && victim->fighting == NULL)
		{
			make_char_fight_char( ch, victim );
			multi_hit( victim, ch, TYPE_UNDEFINED );
		}
	}
	pop_call();
	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;

	push_call("obj_cast_spell(%p,%p,%p,%p,%p)",sn,level,ch,victim,obj);

	if (sn <= 0)
	{
		pop_call();
		return;
	}

	if (sn <= MAX_SKILL && skill_table[sn].slot == -1)
	{
		pop_call();
		return;
	}

	if (is_safe_magic(ch, NULL, sn))
	{
		pop_call();
		return;
	}

	if (sn >= MAX_SKILL || skill_table[sn].spell_fun == 0)
	{
		if (obj != NULL)
		{
			log_printf("obj_cast_spell: Vnum %u bad sn %d.", obj->pIndexData->vnum, sn);
		}
		else
		{
			log_printf("Unknown item cast sn %d", sn);
		}
		pop_call();
		return;
	}

	level  = level * caster_levels(ch) / UMAX(1, ch->level);
	target = skill_table[sn].target;

	switch (target)
	{
		default:
			bug( "obj_cast_spell: bad target for sn %d.", sn );
			pop_call();
			return;

		case TAR_IGNORE:
			vo = NULL;
			break;

		case TAR_CHAR_OFFENSIVE:

			if (victim == ch || victim == NULL)
			{
				if (who_fighting(ch))
				{
					victim = ch->fighting->who;
				}
			}

			if (victim == NULL)
			{
				send_to_char( "You can't do that.\n\r", ch );
				pop_call();
				return;
			}

			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			break;

		case TAR_CHAR_DEFENSIVE:

			if (victim == NULL)
			{
				victim = ch;
			}

			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}

			vo = (void *) victim;
			break;

		case TAR_CHAR_SELF:

			if (victim == NULL)
			{
				victim = ch;
			}

			vo = (void *) ch;
			break;

		case TAR_OBJ_INV:
			if (obj == NULL)
			{
				send_to_char( "You can't do that.\n\r", ch );
				pop_call();
				return;
			}
			vo = (void *) obj;
			break;

		case TAR_OBJ_CHAR_DEF:

			if (victim)
			{
				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_DEFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;

		case TAR_OBJ_CHAR_OFF:

			if (victim)
			{
				if (victim == ch && who_fighting(ch))
				{
					victim = ch->fighting->who;
				}

				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_OFFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;
	}

	target_name = "";

	level = magic_modify(ch, victim, sn, level);

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

	if (target == TAR_CHAR_OFFENSIVE)
	{
		if (victim != ch && victim->fighting == NULL)
		{
			make_char_fight_char( ch, victim );
			multi_hit( victim, ch, TYPE_UNDEFINED );
		}
	}
	pop_call();
	return;
}

/*
	Magical Totem casting spells on the room
*/

void totem_cast_spell( OBJ_DATA *obj )
{
	CHAR_DATA *totem, *rch, *rch_next;
	int sn, level, target;

	push_call("totem_cast_spell(%p)",obj);

	if (obj->in_room == NULL)
	{
		pop_call();
		return;
	}

	if (obj->in_room->area->nplayer == 0)
	{
		pop_call();
		return;
	}

	if ((totem = mob_index[MOB_VNUM_TOTEM]->first_instance) == NULL)
	{
		pop_call();
		return;
	}

	target_name = "";

	STRFREE(totem->short_descr);
	totem->short_descr = STRDUPE(obj->short_descr);

	char_to_room(totem, obj->in_room->vnum);

	act("The air thickens with magic as $n starts to hum.", totem, NULL, NULL, TO_ROOM);

	for (rch = obj->in_room->first_person ; rch ; rch = rch_next)
	{
		rch_next = rch->next_in_room;

		if (rch == totem)
		{
			continue;
		}

		if (IS_NPC(rch) && IS_AFFECTED(rch, AFF_ETHEREAL))
		{
			continue;
		}

		if (is_affected(rch, gsn_anti_magic_shell))
		{
			continue;
		}

		sn = obj->value[number_range(0,3)];

		if (!is_spell(sn))
		{
			continue;
		}

		level  = obj->level;
		level  = magic_modify(totem, rch, sn, level);
		target = skill_table[sn].target;

		switch (target)
		{
			case TAR_OBJ_CHAR_OFF:
				target = TAR_CHAR_OFFENSIVE;
				break;
			case TAR_OBJ_CHAR_DEF:
				target = TAR_CHAR_DEFENSIVE;
				break;
		}

		(*skill_table[sn].spell_fun) (sn, level, totem, rch, target);
	}

	char_to_room(totem, ROOM_VNUM_TOTEM);

	pop_call();
	return;
}

/*
	Takes any offensive spell for a sorcerer and defensive spell
	for a shaman and applies it to all the appropriate char's.
	Costs more mana than the combined casts, but takes less time.
*/

void do_mass( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	CHAR_DATA *victim, *next_vict;
	int sn, sha_mlv, sor_mlv, level, mana, target;

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

	argument = one_argument( argument, arg1 );

	if (arg1[0] == '\0')
	{
		send_to_char( "Cast which what where?\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && multi(ch, gsn_mass) == -1)
	{
		send_to_char( "You can't do that!\n\r", ch );
		pop_call();
		return;
	}

	if (number_percent() > learned(ch, gsn_mass))
	{
		send_to_char("You failed to enter the proper state of mind to amass that much energy!\n\r",ch);
		wait_state(ch, skill_table[gsn_mass].beats);
		pop_call();
		return;
	}

	sn = skill_lookup( arg1 );

	if (sn < 0 || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		if (!IS_NPC(ch) && ch->desc == NULL)
		{
			log_printf("[%u] massing unknown spell: %s", ch->pIndexData->vnum, arg1);
		}
		pop_call();
		return;
	}

	if ((level = can_cast_spell(ch, sn)) == -1)
	{
		pop_call();
		return;
	}

	sha_mlv = (IS_NPC(ch) || IS_IMMORTAL(ch)) ? 100 : ch->pcdata->mclass[CLASS_SHAMAN];
	sor_mlv = (IS_NPC(ch) || IS_IMMORTAL(ch)) ? 100 : ch->pcdata->mclass[CLASS_SORCERER];

	target  = skill_table[sn].target;

	switch (target)
	{
		case TAR_CHAR_OFFENSIVE:
		case TAR_OBJ_CHAR_OFF:
			if (sor_mlv < skill_table[gsn_mass].skill_level[CLASS_SORCERER])
			{
				send_to_char( "You don't have enough skill in the proper class!\n\r", ch );
				pop_call();
				return;
			}
			target = TAR_CHAR_OFFENSIVE;
			break;
		case TAR_CHAR_DEFENSIVE:
		case TAR_OBJ_CHAR_DEF:
			if (sha_mlv < skill_table[gsn_mass].skill_level[CLASS_SHAMAN])
			{
				send_to_char( "You don't have enough skill in the proper class!\n\r", ch );
				pop_call();
				return;
			}
			target = TAR_CHAR_DEFENSIVE;
			break;
		default:
			send_to_char("You would kill yourself trying to amass that much energy!\n\r",ch);
			pop_call();
			return;
 	}

	if (is_safe_magic(ch, NULL, sn))
	{
		pop_call();
		return;
	}

	mana = get_mana(ch, sn) * 5 / 4;

	/*
		Locate targets.
	*/

	switch (target)
	{
		case TAR_CHAR_OFFENSIVE:
			send_to_char("You unleash your magic upon your foes!\n\r", ch);
			break;
		case TAR_CHAR_DEFENSIVE:
			send_to_char("You sent forth your magic to aid your group.\n\r", ch);
			break;
	}

	for (victim = ch->in_room->last_person ; victim ; victim = next_vict)
	{
		next_vict = victim->prev_in_room;

		switch (target)
		{
			case TAR_CHAR_OFFENSIVE:

				if (!can_mass_cast(ch, victim))
				{
					continue;
				}

				if (!IS_IMMORTAL(ch) && ch->mana < mana)
				{
					act("You don't have enough mana for $N.", ch, NULL, victim, TO_CHAR);
					wait_state( ch, skill_table[sn].beats );
					pop_call();
					return;
				}
				if (!IS_IMMORTAL(ch) && number_percent() > learned(ch, sn))
				{
					act("You lost your concentration on $N.", ch, NULL, victim, TO_CHAR);
					ch->mana -= mana / 2;
					continue;
				}

				if (!IS_IMMORTAL(ch))
				{
					ch->mana -= mana;
				}

				level = magic_modify(ch, victim, sn, level);

				(*skill_table[sn].spell_fun) (sn, level, ch, victim, target);

				check_improve(ch, sn);

				if (victim != ch && victim->fighting == NULL)
				{
					make_char_fight_char( ch, victim );
					multi_hit( victim, ch, TYPE_UNDEFINED );
				}
				break;

			case TAR_CHAR_DEFENSIVE:

				if (!is_same_group(ch, victim))
				{
					continue;
				}

				if (is_safe_magic(ch, victim, sn))
				{
					continue;
				}

				if (!IS_IMMORTAL(ch) && ch->mana < mana)
				{
					act("You don't have enough mana for $N.",ch,NULL,victim,TO_CHAR);
					wait_state( ch, skill_table[sn].beats );
					pop_call();
					return;
				}

				if (!IS_IMMORTAL(ch) && number_percent() > learned(ch, sn))
				{
					act("You lost your concentration on $N.",ch,NULL,victim,TO_CHAR);
					ch->mana -= mana / 2;
					continue;
				}
				if (!IS_IMMORTAL(ch))
				{
    					ch->mana -= mana;
    				}

				level = magic_modify(ch, victim, sn, level);

				(*skill_table[sn].spell_fun) ( sn, level, ch, victim, target );

				check_improve(ch, sn);

				break;

		}
	}
	if (IS_AFFECTED(ch, AFF2_QUICKEN))
	{
		wait_state( ch, skill_table[sn].beats * 2 * 4 / 5);
	}
	else
	{
		wait_state( ch, skill_table[sn].beats * 2);
	}
	check_improve(ch, gsn_mass);

	pop_call();
	return;
}

/*
	Finds target in adjusting room and casts the spell on it for
	double mana cost.
*/

void do_range_cast( CHAR_DATA *ch, char *argument )
{
	char *arg1,buf1[MAX_INPUT_LENGTH];
	char *arg2,buf2[MAX_INPUT_LENGTH];
	char *arg3,buf3[MAX_INPUT_LENGTH];
	ROOM_INDEX_DATA *temp_room;
	EXIT_DATA *pexit;
	CHAR_DATA *victim, *next_victim;
	void *vo;
	int mana, sn, dir, level, target;
	long long actn;

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

	if (!IS_NPC(ch) && multi(ch, gsn_range_cast) == -1)
	{
		send_to_char("Better leave the envisioning to the rangecasters.\n\r", ch);
		pop_call();
		return;
	}

	if (strlen( argument) > 120 )
	{
		*(argument+120)='\0';
	}

	target_name = one_argument( argument, buf1 );
	target_name = one_argument( target_name, buf2 );
	target_name = one_argument( target_name, buf3 );

	/*
		Get proper room for given direction
	*/

	if ((dir = direction_door(buf1)) == -1)
	{
		if ((dir = direction_door(buf2)) == -1)
		{
			if ((dir = direction_door(buf3)) == -1)
			{
				send_to_char("Range cast which direction?\n\r",ch);
				pop_call();
				return;
			}

			/* buf3 is direction */

			arg1=buf1;
			arg2=buf2;
			arg3=buf3;
		}

		/* buf2 is direction */

		arg1=buf1;
		arg2=buf3;
		arg3=buf2;
	}
	else
	{
		/* buf1 is direction */

		arg1=buf2;
		arg2=buf3;
		arg3=buf1;
	}

	pexit = get_exit(ch->in_room->vnum, dir);

	if (pexit == NULL
	||  room_index[pexit->to_room]->area != ch->in_room->area
	||  IS_SET(ch->in_room->exit[dir]->exit_info, EX_CLOSED))
	{
		send_to_char( "You can't range cast in that direction!\n\r", ch );
		pop_call();
		return;
	}

	for (victim = room_index[pexit->to_room]->first_person ; victim ; victim = victim->next_in_room)
	{
		if (IS_NPC(victim) && (victim->pIndexData->pShop != NULL))
		{
			send_to_char( "You can't range cast into a shop!\n\r", ch );
			pop_call();
			return;
		}
	}

	if (arg1[0] == '\0')
	{
		send_to_char( "Cast which what where?\n\r", ch );
		pop_call();
		return;
	}

	sn = skill_lookup( arg1 );

	if (sn < 0 || !is_spell(sn))
	{
		if (!IS_NPC(ch) && ch->desc == NULL)
		{
			log_printf("[%u] rangecast unknown spell: %s", ch->pIndexData->vnum, arg1);
		}
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}

	if ((level = can_cast_spell(ch, sn)) == -1)
	{
		pop_call();
		return;
	}

	if (is_safe_magic(ch, NULL, sn))
	{
		pop_call();
		return;
	}

	target = skill_table[sn].target;

	switch (target)
	{
		case TAR_OBJ_CHAR_DEF:
			target = TAR_CHAR_DEFENSIVE;
			break;
		case TAR_OBJ_CHAR_OFF:
			target = TAR_CHAR_OFFENSIVE;
			break;
	}

	if (IS_SET(room_index[pexit->to_room]->room_flags, ROOM_SAFE) && (target != TAR_CHAR_DEFENSIVE))
	{
		send_to_char( "You can't range cast in that direction!\n\r", ch );
		pop_call();
		return;
	}

	mana = 3 * get_mana(ch, sn);

	/*
		Locate targets.
	*/

	victim	= NULL;
	vo		= NULL;

	temp_room = ch->in_room;

	switch ( target )
	{
		default:
			bug( "do_range_cast: bad target for sn %d.", sn );
			pop_call();
			return;

		case TAR_CHAR_SELF:
		case TAR_OBJ_INV:
			send_to_char("That type of target is not allowed at range.\n\r",ch);
			pop_call();
			return;

		case TAR_IGNORE:
			break;

		case TAR_CHAR_OFFENSIVE:

			if (arg2[0] == '\0')
			{
				send_to_char( "Range cast whom?\n\r", ch );
				pop_call();
				return;
			}

			ch->in_room = room_index[pexit->to_room];

			if ((victim = get_char_room(ch, arg2)) == NULL)
			{
				send_to_char( "They aren't there.\n\r", ch );
				ch->in_room = temp_room;

				pop_call();
				return;
			}
			ch->in_room = temp_room;

			if (victim == ch)
			{
				send_to_char( "They aren't there.\n\r", ch );
				pop_call();
				return;
			}

			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			break;

		case TAR_CHAR_DEFENSIVE:
			if (arg2[0] == '\0')
			{
				send_to_char( "Range cast whom?\n\r", ch );
				pop_call();
				return;
			}

			ch->in_room = room_index[pexit->to_room];

			if ((victim = get_char_room( ch, arg2 ) ) == NULL)
			{
				send_to_char( "They aren't there.\n\r", ch );
				ch->in_room = temp_room;

				pop_call();
				return;
			}
			ch->in_room = temp_room;

			if (victim == ch)
			{
				send_to_char( "They aren't there.\n\r", ch );
				pop_call();
				return;
			}

			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}

			vo = (void *) victim;
			break;
	}

	if (!IS_IMMORTAL(ch) && ch->mana < mana)
	{
		send_to_char( "You don't have enough mana.\n\r", ch );
		pop_call();
		return;
	}

	if (number_percent() > learned(ch, gsn_range_cast))
	{
		send_to_char("You envisioned the area but failed to remain focussed.\n\r",ch);
		wait_state(ch, skill_table[sn].beats/2);
		pop_call();
		return;
	}

	wait_state( ch, skill_table[sn].beats);

	send_to_char("You close your eyes, envision the area, and cast!\n\r",ch);

	if (!IS_IMMORTAL(ch) && number_percent() > learned(ch, sn))
	{
		send_to_char( "You lost your concentration.\n\r", ch );
		ch->mana -= mana / 2;
		pop_call();
		return;
	}

	if (!IS_IMMORTAL(ch))
	{
		ch->mana -= mana;
	}

	char_from_room(ch);
	char_to_room(ch, pexit->to_room);

	/* turn off autosac, autoloot */

	actn = ch->act;
	REMOVE_BIT(ch->act, PLR_AUTOSAC|PLR_AUTOLOOT|PLR_AUTO_SPLIT);

	level = magic_modify(ch, victim, sn, level);

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

	check_improve(ch, sn);

	if (target == TAR_CHAR_OFFENSIVE)
	{
		make_char_fight_char( ch, victim );
	}

	ch->act = actn;

	char_from_room(ch);
	char_to_room(ch, temp_room->vnum);

	/*
		Move some creatures into room of caster
	*/

	if (target == TAR_CHAR_DEFENSIVE)
	{
		pop_call();
		return;
	}

	if (target == TAR_IGNORE)
	{
		if (skill_table[sn].minimum_position != POS_FIGHTING)
		{
			pop_call();
			return;
		}
	}

	for (victim = room_index[pexit->to_room]->last_person ; victim ; victim = next_victim)
	{
		next_victim = victim->prev_in_room;

		if (victim->fighting != NULL && victim->fighting->who != ch)
		{
			continue;
		}

		if (victim->fighting == NULL && number_bits(2) != 0)
		{
			continue;
		}

		if (!IS_NPC(victim) || !IS_IMMORTAL(victim) || IS_AFFECTED(victim, AFF_ETHEREAL) || number_bits(3) == 0)
		{
			continue;
		}

		char_from_room(victim);
		char_to_room(victim, ch->in_room->vnum);

		act("$n arrives, glaring around angrily!", victim, NULL, NULL, TO_ROOM);
		if (!IS_NPC(ch) && victim->npcdata->pvnum_last_hit == ch->pcdata->pvnum)
		{
			make_char_fight_char( ch, victim );
			multi_hit( victim, ch, TYPE_UNDEFINED );
		}
	}
	pop_call();
	return;
}

/*
	Returns -1 if one cannot cast the spell, otherwise it Returns the
	spell level - Scandum 01/04/2002
*/

int can_cast_spell( CHAR_DATA *ch, int sn )
{
	int level;

	push_call("can_cast_spell(%p,%p)",ch,sn);

	if (IS_NPC(ch))
	{
		level = UMAX(ch->level * 3 / 4, 1);

		pop_call();
		return(level);
	}

	if (!IS_IMMORTAL(ch))
	{
		if (!IS_SET(skill_table[sn].race, 1 << ch->race) && multi(ch, sn) == -1)
		{
			send_to_char( "You cannot cast that spell.\n\r", ch );
			pop_call();
			return(-1);
		}
	}

	if (IS_IMMORTAL(ch) || IS_SET(skill_table[sn].race, 1 << ch->race))
	{
		level = ch->level;
	}
	else
	{
		level = multi_spell_level(ch, sn);

		level = level * ch->pcdata->learned[sn] / 100 + 1;
	}

	/*
		Added SFOL check and bonus based on int of caster, ranging from
		103% to 139% for a 0 to 10 reinc lvl 95 human - Scandum 30-03-2002
	*/

	if (IS_IMMORTAL(ch)
	|| (skill_table[sn].follower == SFOL_NONE)
	|| (skill_table[sn].follower & SFOL_ULMO 	&& ch->pcdata->god == GOD_ULMO)
	|| (skill_table[sn].follower & SFOL_DEMISE   && ch->pcdata->god == GOD_DEMISE)
	|| (skill_table[sn].follower & SFOL_GAIA     && ch->pcdata->god == GOD_GAIA)
	|| (skill_table[sn].follower & SFOL_ILUVATAR && ch->pcdata->god == GOD_ILUVATAR)
	|| (skill_table[sn].follower & SFOL_HYPNOS   && ch->pcdata->god == GOD_HYPNOS)
	|| (skill_table[sn].follower & SFOL_MANWE    && ch->pcdata->god == GOD_MANWE))
	{
		if (get_curr_int(ch) > 28)
		{
				level = level * get_curr_int(ch) / 28;
		}
	}
	else
	{
		send_to_char( "You lack the skill with the elements to cast that spell.\n\r", ch );

		pop_call();
		return(-1);
	}
	pop_call();
	return(level);
}

/*
	Returns TRUE and gives appropriate spams if one cannot cast a spell
	on the victim, if victim is NULL only room and ch based stuff is
	checked - Scandum 01-04-2002
*/

bool is_safe_magic( CHAR_DATA *ch, CHAR_DATA *victim, int sn)
{
	push_call("is_safe_magic(%p,%p)",ch,victim);

	if (is_affected(ch, gsn_anti_magic_shell))
	{
		if ((victim && victim != ch) || skill_table[sn].target == TAR_IGNORE)
		{
			send_to_char("The flows of magic shatter against the shell surrounding you.\n\r", ch);
			pop_call();
			return TRUE;
		}
	}

	if (find_keeper(ch) != NULL)
	{
		ch_printf(ch, "%s%s tells you 'No magic in here! You punk!'\n\r", get_color_string(ch,COLOR_SPEACH,VT102_BOLD), capitalize(find_keeper(ch)->short_descr));
		pop_call();
		return TRUE;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		if (skill_table[sn].target == TAR_IGNORE)
		{
			if (skill_table[sn].minimum_position == POS_FIGHTING)
			{
				send_to_char( "You cannot do that here.\n\r", ch);
				pop_call();
				return TRUE;
			}
		}
		if (skill_table[sn].target == TAR_CHAR_OFFENSIVE
		||  skill_table[sn].target == TAR_OBJ_CHAR_OFF)
		{
			send_to_char( "You cannot do that here.\n\r", ch);
			pop_call();
			return TRUE;
		}
	}

	if (ch->position < skill_table[sn].minimum_position)
	{
		send_to_char( "You can't concentrate enough.\n\r", ch );
		pop_call();
		return TRUE;
	}

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (victim == ch)
	{
		pop_call();
		return FALSE;
	}

	if (is_affected(victim, gsn_anti_magic_shell))
	{
		act("The flows of magic shatter against the shell surrounding $N.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return TRUE;
	}

	if (ch->fighting != NULL && ch->fighting->who == victim)
	{
		pop_call();
		return FALSE;
	}

	if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
	{
		pop_call();
		return FALSE;
	}

	switch (skill_table[sn].target)
	{
		default:

			bug( "is_safe_magic: bad target for sn %d.", sn );
			pop_call();
			return TRUE;
			break;

		case TAR_CHAR_OFFENSIVE:
		case TAR_OBJ_CHAR_OFF:
			if (IS_NPC(ch) && ch->fighting == NULL && ch->hit < ch->max_hit / 2)
			{
				if (ch->desc == NULL)
				{
					pop_call();
					return TRUE;
				}
			}

			if (ch->desc)
			{
				if (!IS_NPC(victim))
				{
					send_to_char( "You must MURDER a player.\n\r", ch);
					pop_call();
					return TRUE;
				}
			}

			if (!IS_NPC(ch))
			{
				ch->pcdata->just_died_ctr = 0;
			}

			if (IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL)
			{
				if (victim->master == ch)
				{
					raw_kill( victim );
					pop_call();
					return TRUE;
				}
			}

			if (ch->fighting == NULL || ch->fighting->who != victim )
			{
				if (!IS_NPC(ch) && IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM))
				{
					send_to_char( "You cannot kill a slave.\n\r", ch);
					pop_call();
					return TRUE;
				}
			}

			if (IS_NPC(victim) && victim->fighting != NULL
			&& !IS_NPC(ch) && !is_same_group(ch, victim->fighting->who))
			{
				ch_printf(ch, "%s seems to be busy!\n\r", capitalize(get_name(victim)));
				pop_call();
				return TRUE;
			}

			if (check_recently_fought(ch, victim))
			{
				ch_printf(ch, "%s was recently fought.  Try later.\n\r", capitalize(get_name(victim)));
				pop_call();
				return TRUE;
			}
			break;

		case TAR_CHAR_DEFENSIVE:
		case TAR_OBJ_CHAR_DEF:

			if (!IS_NPC(ch) && victim->fighting != NULL)
			{
				if (!IS_NPC(victim) && !IS_NPC(victim->fighting->who))
				{
					ch_printf(ch ,"%s seems to be busy!\n\r", capitalize(get_name(victim)));
					pop_call();
					return TRUE;
				}
				if (!is_same_group(ch, victim))
				{
					ch_printf(ch ,"%s seems to be busy!\n\r", capitalize(get_name(victim)));
					pop_call();
					return TRUE;
				}
			}
			break;
	}
	pop_call();
	return FALSE;
}

/*
	true if victim is a legal target for a mass attack - Scandum 01/04/2002
*/

bool can_mass_cast( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("can_mass_cast(%p,%p)",ch,victim);

	if (victim == ch)
	{
		pop_call();
		return FALSE;
	}

	if (is_affected(victim, gsn_anti_magic_shell))
	{
		act("The flows of magic shatter against a shell surrounding $N.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (victim->fighting && victim->fighting->who == ch)
	{
		pop_call();
		return TRUE;
	}

	if (victim->fighting && !is_same_group(ch, victim->fighting->who))
	{
		pop_call();
		return FALSE;
	}

	if (IS_NPC(victim) && IS_AFFECTED(victim, AFF_ETHEREAL))
	{
		pop_call();
		return FALSE;
	}

	if (is_same_group(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
	{
		pop_call();
		return TRUE;
	}

	if (IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM))
	{
		pop_call();
		return FALSE;
	}

	if (!IS_NPC(ch) && !IS_NPC(victim))
	{
		pop_call();
		return FALSE;
	}

	if (IS_NPC(ch) && ch->desc && !IS_NPC(victim))
	{
		pop_call();
		return FALSE;
	}

	if (check_recently_fought(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}

void do_mana( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int sn;

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

	if (*argument == '\0')
	{
		send_to_char("Usage: mana <spell name>.\n\r", ch);
		pop_call();
		return;
	}

	sn = skill_lookup( argument );
	if (sn < 0 || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}

	if ((can_cast_spell(ch, sn)) == -1)
	{
		pop_call();
		return;
	}

	sprintf( buf, "Mana usage for '%s' is: %d\n\r",
	skill_table[sn].name, get_mana( ch, sn));
	send_to_char( buf, ch);
	pop_call();
	return;
}

int get_mana( CHAR_DATA *ch, int sn)
{
	int mana,mnx,cnt;

	push_call("get_mana(%p,%p)",ch,sn);

	if (IS_NPC(ch) || IS_SET(skill_table[sn].race, 1 << ch->race))
	{
		mana = skill_table[sn].min_mana;
	}
	else
	{
		cnt = multi(ch, sn);

		mnx = skill_table[sn].skill_level[cnt] / 2 + 1;

		mana = 50 * mnx / (ch->pcdata->mclass[cnt] + mnx - skill_table[sn].skill_level[cnt]) - (get_curr_wis(ch)-13) / 2;

		mana = UMAX(skill_table[sn].min_mana, mana);
	}

	if (IS_AFFECTED(ch, AFF2_QUICKEN))
	{
		mana += mana;
	}

	pop_call();
	return(mana);
}

void do_move( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int sn, cnt, move;

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

	sn = skill_lookup( argument );
	if( sn < 0 || is_spell(sn))
	{
		send_to_char( "That doesn't cost any movement.\n\r", ch );
		pop_call();
		return;
	}

	cnt = multi( ch, sn);

	if(cnt==-1 && !IS_NPC(ch))
	{
		send_to_char( "You can't do that.\n\r", ch );
		pop_call();
		return;
	}
	move = IS_NPC(ch) ? 0 : skill_table[sn].min_mana;

	sprintf(buf,"Movement usage for '%s' is: %d\n\r",skill_table[sn].name,move);
	send_to_char(buf,ch);
	pop_call();
	return;
}

bool is_spell(int sn)
{
	push_call("is_spell(%p)",sn);

	if (sn > 0 && sn < MAX_SKILL && IS_SET(skill_table[sn].flags, FSKILL_SPELL))
	{
		pop_call();
  		return TRUE;
  	}

	pop_call();
	return FALSE;
}

int caster_levels( CHAR_DATA *ch )
{
	int levels;

	push_call("caster_levels(%p)",ch);

	if (IS_NPC(ch))
	{
		pop_call();
		return( ch->level );
	}

	levels  = ch->pcdata->mclass[ CLASS_DRUID     ];
	levels += ch->pcdata->mclass[ CLASS_SORCERER  ];
	levels += ch->pcdata->mclass[ CLASS_SHAMAN    ];
	levels += ch->pcdata->mclass[ CLASS_WARLOCK   ];
	/*
		Non specialist caster-levels count only half	21/10/2000 - Manwe
	*/
	levels += ch->pcdata->mclass[ CLASS_WARRIOR   ] / 2;
	levels += ch->pcdata->mclass[ CLASS_MARAUDER  ] / 2;
	levels += ch->pcdata->mclass[ CLASS_GLADIATOR ] / 2;
	levels += ch->pcdata->mclass[ CLASS_NINJA     ] / 2;

	if (levels > ch->level)
	{
		levels = ch->level;
	}
	pop_call();
	return( levels );
}

int magic_modify( CHAR_DATA *ch, CHAR_DATA *victim, int sn, int level )
{
	int dam_type = DAM_THRUST;

	push_call("damage_modify(%p,%p,%p,%p)",ch,victim,sn,level);

	if (level <= 0)
	{
		pop_call();
		return 0;
	}

	if (victim == NULL)
	{
		pop_call();
		return level;
	}

	switch (skill_table[sn].target)
	{
		case TAR_CHAR_DEFENSIVE:
		case TAR_OBJ_CHAR_DEF:
			if (!IS_IMMORTAL(ch) && victim != ch)
			{
				if (level > victim->level * 2)
				{
					level = victim->level * 2;
				}
			}
			break;
	}

	dam_type = skill_table[sn].dam_type;

	if (dam_type == DAM_NONE)
	{
		pop_call();
		return level;
	}

	if (dam_type == god_table[which_god(victim)].resistance)
	{
		level = level * 75 / 100;
	}

	if (IS_UNDEAD(victim))
	{
		if (IS_SET(DAM_LIFE|DAM_POISON|DAM_EVIL, dam_type))
		{
			level = level * 75 / 100;
		}
	}

	if (IS_SET(race_table[victim->race].res_low, dam_type))
	{
		level = level * 90 / 100;
	}

	if (IS_SET(race_table[victim->race].res_high, dam_type))
	{
		level = level * 80 / 100;
	}

	if (IS_SET(race_table[victim->race].vul_low, dam_type))
	{
		level = level * 110 / 100;
	}

	if (IS_SET(race_table[victim->race].vul_high, dam_type))
	{
		level = level * 120 / 100;
	}

	level = UMAX(1, level);

	pop_call();
	return level;
}

int multi_spell_level( CHAR_DATA *ch, int sn)
{
	int cnt, mlv;

	push_call("multi_spell_level(%p,%p)",ch,sn);

	mlv = 0;

	if (IS_NPC(ch))
	{
		mlv = ch->level;
		pop_call();
		return(mlv);
	}

	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (skill_table[sn].skill_level[cnt] < MAX_LEVEL)
		{
			mlv += ch->pcdata->mclass[cnt];
		}
		else if (cnt >= 4)
		{
			mlv += ch->pcdata->mclass[cnt] * 3 / 4;
		}
		else
		{
			mlv += ch->pcdata->mclass[cnt] * 1 / 4;
		}
	}
	if (mlv > ch->level)
	{
		mlv = ch->level;
	}
	if (ch->race == RACE_HUMAN)
	{
		mlv += ch->pcdata->reincarnation;
	}
	pop_call();
	return(mlv);
}

ROOM_INDEX_DATA *get_rift_room( CHAR_DATA *ch, int rift_number)
{
	ROOM_INDEX_DATA *rift_room;

	push_call("get_rift_room(%p,%p)",ch,rift_number);

	srand(value + ch->pcdata->pvnum + 1);

	while (TRUE)
	{
		rift_room = get_room_index(rand() % 20000);

		if (rift_room == NULL)
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_SAFE))
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_IS_CASTLE))
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_PET_SHOP))
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_PRIVATE))
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_SOLITARY))
		{
			continue;
		}
		if (IS_SET(rift_room->room_flags, ROOM_NO_RECALL))
		{
			continue;
		}
		if (rift_room->sector_type == SECT_ETHEREAL)
		{
			continue;
		}
		if (rift_room->sector_type == SECT_ASTRAL)
		{
			continue;
		}
		if (IS_SET(rift_room->area->flags, AFLAG_NOTELEPORT))
		{
			continue;
		}
		if (IS_SET(rift_room->area->flags, AFLAG_NORECALL))
		{
			continue;
		}
		if (IS_SET(rift_room->area->flags, AFLAG_NORIP))
		{
			continue;
		}
		if (!IS_IMMORTAL(ch))
		{
			if (ch->level < rift_room->area->low_hard_range)
			{
				continue;
			}
			if (ch->level > rift_room->area->hi_hard_range)
			{
				continue;
			}
		}
		break;
	}
	pop_call();
	return rift_room;
}

/*
	Spell functions.
*/

DO_SPELL(spell_acid_blast)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_acid_blast(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level*3+50, level*5+100);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_armor)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_armor(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type = sn;

	if (!IS_NPC(ch) && ch->pcdata->mclass[CLASS_DRUID] > 0)
	{
		af.duration  = 48;
		af.modifier  = -15;
	}
	else
	{
		af.duration  = 24;
		af.modifier  = -5;
	}
	af.location  = APPLY_AC;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	act( "$n's armor begins to glow softly as it is enhanced by a cantrip.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your armor begins to glow softly as it is enhanced by a cantrip.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_bless)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_bless(%p,%p,%p,%p)",sn,level,ch,vo);

	if( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = 6+level/2;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;

	af.location  = APPLY_HITROLL;
	af.modifier  = level/9;
	affect_to_char( victim, &af );

	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = 0 - level / 8;
	affect_to_char( victim, &af );

	act( "A powerful blessing is laid upon $n.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "A powerful blessing is laid upon you.\n\r", victim );
	pop_call();
	return;
}

DO_SPELL(spell_blindness)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_blindness(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_BLIND) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF_TRUESIGHT ))
	{
		act( "$N sees through the veil on reality you try to impose.", ch, NULL, victim, TO_CHAR );
		act( "You see through the veil on reality $n attempts to impose.", ch, NULL, victim, TO_VICT );
		pop_call();
		return;
	}

	if ( saves_spell( level, ch, victim ) )
	{
		send_to_char( "Nothing happens.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_HITROLL;
	af.modifier  = -2*level/5;
	af.duration  = 1+level/5;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_BLIND;
	affect_to_char( victim, &af );

	send_to_char( "You are blinded!\n\r", victim );

	if ( ch != victim )
	{
		send_to_char( "Your foe is now blinded.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_burning_hands)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_burning_hands(%p,%p,%p,%p)",sn,level,ch,vo);

	dam  = number_range( level+50, level+100 );

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_call_lightning)
{
	CHAR_DATA *vch, *vch_next;
	int dam, door, temp_vnum;
	EXIT_DATA *pexit;

	push_call("spell_call_lightning(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( !IS_OUTSIDE(ch) )
	{
		send_to_char( "You must be out of doors.\n\r", ch );
		pop_call();
		return;
	}

	if (NO_WEATHER_SECT(ch->in_room->sector_type))
	{
		send_to_char( "You must be out of doors.\n\r", ch );
		pop_call();
		return;
	}

	if ( ch->in_room->area->weather_info->sky < SKY_RAINING )
	{
		send_to_char( "You need bad weather.\n\r", ch );
		pop_call();
		return;
	}

	send_to_char( "Elemental lightning strikes your foes!\n\r", ch );
	act( "$n calls elemental lightning to strike $s foes!", ch, NULL, NULL, TO_ROOM );

	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next = vch->prev_in_room;

		if (!can_mass_cast(ch, vch))
		{
			continue;
		}
		dam = number_range(level*1, level*4);
		damage( ch, vch, saves_spell(level, ch, vch) ? dam/2 : dam, sn );
	}

	temp_vnum = ch->in_room->vnum;

	for (door = 0 ; door < 6 ; door++)
	{
		if ((pexit = get_exit(temp_vnum, door)) && pexit->to_room != temp_vnum)
		{
			ch->in_room = room_index[pexit->to_room];
			act("Lightning flashes in the sky.", ch, NULL, NULL, TO_ROOM );
		}
	}
	ch->in_room = room_index[temp_vnum];

	pop_call();
	return;
}

DO_SPELL(spell_chain_lightning)
{
	CHAR_DATA *vch, *vch_next;
	ROOM_INDEX_DATA *temp_room = ch->in_room;
	int dam, targets;

	push_call("spell_chain_lightning(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!IS_OUTSIDE(ch) || NO_WEATHER_SECT(ch->in_room->sector_type))
	{
		send_to_char( "You must be out of doors.\n\r", ch );
		pop_call();
		return;
	}

	if (ch->in_room->area->weather_info->sky < SKY_RAINING)
	{
		level = level * 2 / 3;
	}

	if (ch->in_room->area->weather_info->sky < SKY_LIGHTNING)
	{
		level = level * 2 / 3;
	}

	act( "You call forth a bolt of chain lightning!", ch, NULL, NULL, TO_CHAR );
	act( "$n calls forth a bolt of chain lightning!", ch, NULL, NULL, TO_ROOM );

	while (level > 0)
	{
		for (targets = 0, vch = ch->in_room->last_person ; vch ; vch = vch_next)
		{
			vch_next = vch->prev_in_room;

			if (!can_mass_cast(ch, vch))
			{
				continue;
			}

			dam     = saves_spell(level, ch, vch) ? dice(level, 3) : dice(level, 6);
			level  -= 20;
			targets += 1;

			switch (number_bits(2))
			{
				case 0:
					act("The searing bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
					act("The searing bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
					break;
				case 1:
					act("The sizzling bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
					act("The sizzling bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
					break;
				case 2:
					act("The crackling bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
					act("The crackling bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
					break;
				case 3:
					act("The fiery bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
					act("The fiery bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
					break;
			}
			damage( ch, vch, dam, sn );

			if (level <= 0)
			{
				break;
			}
		}
		if (level > 0)
		{
			if (targets == 1)
			{
				vch     = ch;
				dam     = saves_spell(level, ch, vch) ? dice(level, 6) : dice(level, 3);
				level  -= 20;

				switch (number_bits(2))
				{
					case 0:
						act("The searing bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
						act("The searing bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
						break;
					case 1:
						act("The sizzling bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
						act("The sizzling bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
						break;
					case 2:
						act("The crackling bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
						act("The crackling bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
						break;
					case 3:
						act("The fiery bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
						act("The fiery bolt of chain lightning arcs to $n.",  vch, NULL, NULL, TO_ROOM);
						break;
				}
				damage( ch, vch, dam, sn );
			}

			if (ch->in_room != temp_room)
			{
				send_to_room("The bolt of chain lightning loses power and fizzles out.\n\r", temp_room);
				pop_call();
				return;
			}

			if (targets == 0)
			{
				act("You catch the bolt of lightning and send it back into the sky.",   ch, NULL, NULL, TO_CHAR);
				act("$n catches the bolt of lightning and sends it back into the sky.", ch, NULL, NULL, TO_ROOM);
				pop_call();
				return;
			}
		}
	}

	switch (number_bits(2))
	{
		case 0: send_to_room("The searing bolt of chain lightning loses power and fizzles out.\n\r",          temp_room); break;
		case 1: send_to_room("The sizzling bolt of chain lightning arcs to the ground and dissipates.\n\r",   temp_room); break;
		case 2: send_to_room("The crackling arc of chain lightning strikes the ground and vanishes.\n\r",     temp_room); break;
		case 3: send_to_room("The fiery bolt of chain lightning loses power before reaching its target.\n\r", temp_room); break;
	}

	pop_call();
	return;
}

DO_SPELL(spell_cause_light)
{
	push_call("spell_cause_light(%p,%p,%p,%p)",sn,level,ch,vo);

	damage( ch, (CHAR_DATA *) vo, dice(1, 15) + level / 2, sn );

	pop_call();
	return;
}

DO_SPELL(spell_cause_serious)
{
	push_call("spell_cause_serious(%p,%p,%p,%p)",sn,level,ch,vo);

	damage( ch, (CHAR_DATA *) vo, dice(1, 25) + level * 2 / 3, sn );

	pop_call();
	return;
}

DO_SPELL(spell_cause_critical)
{
	push_call("spell_cause_critical(%p,%p,%p,%p)",sn,level,ch,vo);

	damage( ch, (CHAR_DATA *) vo, dice(1, 50) + level, sn );

	pop_call();
	return;
}

DO_SPELL(spell_change_sex)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_change_sex(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}
	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level/4;
	af.location  = APPLY_SEX;

	if (victim->sex <= 0)
	{
		if (number_bits(1) == 0)
		{
			af.modifier  = 1;
		}
		else
		{
			af.modifier  = 2;
		}
	}
	else if (victim->sex == 1)
	{
		if (number_bits(1) == 0)
		{
			af.modifier  = 1;
		}
		else
		{
			af.modifier  = -1;
		}
	}
	else if (victim->sex >= 2)
	{
		if (number_bits(1) == 0)
		{
			af.modifier  = -1;
		}
		else
		{
			af.modifier  = -2;
		}
	}
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	send_to_char( "You writhe in agony as your gender changes.\n\r", victim );
	act( "$n writhes in agony as $s gender changes.", victim, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_charm_person)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_charm_person(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "You like yourself even better!\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_NPC(victim) || !can_mass_cast(ch, victim))
	{
		send_to_char( "They seem to be unaffected by your magic.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF_CHARM))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	if (level/3 < victim->level
	||  saves_spell(level, ch, victim)
	||  get_pets(ch) >= 2)
	{
		do_say(victim, "I don't want to be charmed!");
		act( "$n suddenly looks VERY angry!",victim,NULL,NULL,TO_ROOM);
		if (victim->fighting == NULL)
		{
			make_char_fight_char( ch, victim );
			multi_hit(victim, ch, TYPE_UNDEFINED);
		}
		pop_call();
		return;
	}

	if ( victim->master )
	{
		stop_follower( victim );
	}

	add_follower( victim, ch );
	af.type      = sn;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_CHARM;
	affect_to_char( victim, &af );

	act( "Isn't $n just so nice?", ch, NULL, victim, TO_VICT );
	act( "$N looks at you with adoring eyes.", ch, NULL, victim, TO_CHAR );
	act( "$N looks at $n with adoring eyes.",  ch, NULL, victim, TO_NOTVICT );
	pop_call();
	return;
}

DO_SPELL(spell_chill_touch)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;

	int dam;

	push_call("spell_chill_touch(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level+10, level+130);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	else if (number_bits(1) == 0)
	{
		AFFECT_DATA af;

		af.type      = sn;
		af.duration  = 1;
		if (!IS_NPC(victim))
		{
			af.location  = APPLY_STR;
		}
		else
		{
			af.location  = APPLY_DAMROLL;
		}
		af.modifier  = -1;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;
		affect_join( victim, &af );
	}

	damage( ch, victim, dam, sn );
	pop_call();
	return;
}

DO_SPELL(spell_stone_fist)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	int body_part = 0;

	push_call("spell_stone_fist(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type = sn;

	if (which_god(victim) == GOD_GAIA)
	{
		af.duration  = 24;
	}
	else
	{
		af.duration  = 8;
	}
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	if (IS_NPC(victim) && IS_SET(victim->act, ACT_BODY))
	{
		body_part = victim->pIndexData->attack_parts;
	}
	else if (!IS_NPC(victim) || IS_SET(victim->act, ACT_RACE))
	{
		body_part = race_table[victim->race].attack_parts;
	}

	if (IS_SET(body_part, BODY_TENTACLE))
	{
		act( "$n's tentacles turn to stone.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "Your tentacles turn to stone.\n\r", victim );
	}
	else if (IS_SET(body_part, BODY_CLAW))
	{
		act( "$n's claws turn to stone.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "Your claws turn to stone.\n\r", victim );
	}
	else if (IS_SET(body_part, BODY_BRANCH))
	{
		act( "$n's branches turn to stone.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "Your branches turn to stone.\n\r", victim );
	}
	else
	{
		act( "$n's fists turn to stone.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "Your fists turn to stone.\n\r", victim );
	}
	pop_call();
	return;
}

DO_SPELL(spell_color_spray)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_color_spray)",sn,level,ch,vo);

	dam = number_range( level*3+30, level*5+40 );

	if ( saves_spell( level, ch, victim ) )
	{
		damage( ch, victim, dam/2, sn);
	}
	else
	{
		/*
			Added blindness as an extra effect to this spell,
			21/10/2000 - Manwe
			Lets not make it too easy pls, merged the two spells into one
			01/04/2002 - Scandum
		*/

		damage( ch, victim, dam, sn );

		if (ch->in_room == victim->in_room && number_bits(3) == 0 && !IS_AFFECTED(victim, AFF_BLIND))
		{
			AFFECT_DATA af;

			af.type      = gsn_blindness;
			af.location  = APPLY_HITROLL;
			af.modifier  = -1*level/5;
			af.duration  = level/10;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF_BLIND;
			affect_to_char( victim, &af );

			send_to_char( "You are blinded by a dazzling ray of light!\n\r", victim );
			if (ch != victim)
			{
				send_to_char( "A dazzling ray of light blinds your foe.\n\r", ch );
			}
		}
	}

	pop_call();
	return;
}

DO_SPELL(spell_continual_light)
{
	OBJ_DATA *light;

	push_call("spell_continual_light(%p,%p,%p,%p)",sn,level,ch,vo);

	light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ), 0 );
	light->timer = level / 2;
	light->level = level;
	act( "Shards of iridescent light collide to form a dazzling ball.", ch, NULL, NULL, TO_CHAR );
	act( "Shards of iridescent light collide to form a dazzling ball.", ch, NULL, NULL, TO_ROOM );
	obj_to_room( light, ch->in_room->vnum );
	pop_call();
	return;
}

DO_SPELL(spell_control_weather)
{
	push_call("spell_control_weather(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!strcasecmp(target_name, "wet"))
	{
		ch->in_room->area->weather_info->change		+= 1 + level / 33;
	}
	else if (!strcasecmp(target_name, "dry"))
	{
		ch->in_room->area->weather_info->change		-= 1 + level / 33;
	}
	else if (!strcasecmp(target_name, "windy"))
	{
		ch->in_room->area->weather_info->wind_speed	+= 1 + level / 33;
	}
	else if (!strcasecmp(target_name, "calm"))
	{
		ch->in_room->area->weather_info->wind_speed	-= 1 + level / 33;
	}
	else
	{
		send_to_char ("Do you want the weather calm, windy, wet, or dry?\n\r", ch );
		pop_call();
		return;
	}
	send_to_char( "Ok.\n\r", ch );
	pop_call();
	return;
}

DO_SPELL(spell_feast)
{
	CHAR_DATA *fch;

	push_call("spell_feast(%p,%p,%p,%p)",sn,level,ch,vo);

	/*
		Added blood feast for undead and vampiric races - Scandum 01/04/2002
	*/

	if (rspec_req(ch, RSPEC_VAMPIRIC) || rspec_req(ch, RSPEC_UNDEAD))
	{
		act( "$n spreads $s arms and blood spurts forth from $s opened hands.",     ch, NULL, NULL, TO_ROOM );
		act( "You spread your arms and blood spurts forth from your opened hands.", ch, NULL, NULL, TO_CHAR );
		act( "Everyone in the room joins you as you drink your fill.",              ch, NULL, NULL, TO_CHAR );

		gain_condition( ch, COND_FULL,   50 );
		gain_condition( ch, COND_THIRST, 50 );

		for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (!IS_NPC(fch) && fch->position >= POS_RESTING && fch != ch)
			{
				if (!rspec_req(fch,RSPEC_VAMPIRIC) && !rspec_req(fch,RSPEC_UNDEAD))
				{
					send_to_char( "You turn away your head in dismay as the undeads drink.\n\r", fch );
				}
				else
				{
					gain_condition( fch, COND_FULL,   50 );
					gain_condition( fch, COND_THIRST, 50 );
					send_to_char( "You join in the blood feast and drink your fill.\n\r", fch );
				}
			}
		}
	}
	else
	{
		act( "$n creates a large selection of food and drinks.",     ch, NULL, NULL, TO_ROOM );
		act( "You create a large selection of food and drinks.",     ch, NULL, NULL, TO_CHAR );
		act( "Everyone in the room joins you as you eat your fill.", ch, NULL, NULL, TO_CHAR );

		gain_condition( ch, COND_FULL, 50 );
		gain_condition( ch, COND_THIRST, 50 );

		for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (!IS_NPC(fch) && fch->position >= POS_RESTING && fch != ch)
			{
				if (!rspec_req(fch,RSPEC_VAMPIRIC) && !rspec_req(fch,RSPEC_UNDEAD))
				{
					gain_condition( fch, COND_FULL, 50 );
					gain_condition( fch, COND_THIRST, 50 );
					send_to_char( "You join in the feast and eat your fill.\n\r", fch );
				}
				else
				{
					send_to_char( "You turn away your head in dismay as the mortals eat.\n\r", fch );
				}
			}
		}
	}
	pop_call();
	return;
}

DO_SPELL(spell_restore)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal, scale_top, scale_bot;
	char buf[MAX_INPUT_LENGTH];

	push_call("spell_restore(%p,%p,%p,%p)",sn,level,ch,vo);

	scale_top = 10;  /* The fraction for the hp/mana ratio */
	scale_bot = 7;

	if (value == -1 || value > ch->mana )
	{
		value = ch->mana;
	}

	heal = value * scale_top / scale_bot ;

	if (victim->hit + heal > victim->max_hit)
	{
		heal = victim->max_hit - victim->hit ;
	}

	value = heal * scale_bot / scale_top;

	sprintf( buf, "Restoring %d hitpoints for %d mana.\n\r", heal, value + get_mana(ch,sn));
	send_to_char( buf, ch);

	victim->hit += heal;
	ch->mana -= value;

	update_pos( victim );
	send_to_char( "You are filled with an overwhelming feeling of warmth.\n\r", victim );
	affect_strip(victim, gsn_critical_hit);
	if ( ch != victim )
	{
		send_to_char( "You restore them.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_energy_shift)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal, scale_top, scale_bot;
	char buf[MAX_INPUT_LENGTH];

	push_call("spell_energy_shift(%p,%p,%p,%p)",sn,level,ch,vo);

	scale_top = 65;  /* The fraction for the mana_to/mana_from ratio */
	scale_bot = 100;

	if( value == -1 || value > ch->mana )
	{
		value = ch->mana;
	}

	heal = value * scale_top / scale_bot ;
	if( victim->mana + heal > victim->max_mana )
	{
		heal = victim->max_mana - victim->mana ;
	}
	value = ( heal * scale_bot / scale_top );

	sprintf( buf, "Shifting %d mana for %d mana.\n\r", heal, value + get_mana(ch,sn));
	send_to_char( buf, ch);

	victim->mana += heal;
	ch->mana -= value;

	update_pos( victim );
	send_to_char( "You feel a surge of power.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "You transfer energy to them.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_induction)
{
	int heal, scale_top, scale_bot;
	char buf[MAX_INPUT_LENGTH];

	push_call("spell_induction(%p,%p,%p,%p)",sn,level,ch,vo);

	scale_top = 7;  /* The fraction for the mana_to/hp_from ratio */
	scale_bot = 10;

	if (value < 0 || value > ch->hit - 10 )
	{
		value = ch->hit-10;
	}

	heal = value * scale_top / scale_bot;

	if (ch->mana + heal > ch->max_mana)
	{
		heal = ch->max_mana - ch->mana ;
     }

	if (heal < 0)
	{
		heal = 0;
	}
	value = heal * scale_bot / scale_top;

	sprintf( buf, "Inducing %d mana points for %d hitpoints.\n\r", heal, value );
	send_to_char( buf, ch);

	ch->mana += heal;
	ch->hit -= value;

	update_pos( ch );
	if (heal > 0)
	{
		send_to_char( "You feel a surge of power.\n\r", ch );
		act( "$n drains $s strength to further $s magic.", ch, NULL, NULL, TO_ROOM);
	}
	pop_call();
	return;
}

DO_SPELL(spell_create_food)
{
	OBJ_DATA *mushroom;

	push_call("spell_create_food(%p,%p,%p,%p)",sn,level,ch,vo);

	mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ), 0 );
	mushroom->value[0] = 5 + level;
	act( "$p suddenly appears.", ch, mushroom, NULL, TO_ROOM );
	act( "$p suddenly appears.", ch, mushroom, NULL, TO_CHAR );
	obj_to_room( mushroom, ch->in_room->vnum );

	pop_call();
	return;
}

DO_SPELL(spell_create_spring)
{
	OBJ_DATA *spring;

	push_call("spell_create_spring(%p,%p,%p,%p)",sn,level,ch,vo);

	spring = create_object( get_obj_index( OBJ_VNUM_SPRING ), 0 );
	spring->timer = level;
	act( "Tracing a ring before you, the graceful flow of a mystical spring emerges.", ch, spring, NULL, TO_CHAR );
	act( "As $n traces a ring through the air, the graceful flow of a mystical spring emerges.", ch, spring, NULL, TO_ROOM );
	obj_to_room( spring, ch->in_room->vnum );

	pop_call();
	return;
}

DO_SPELL(spell_ice_arrow)
{
	OBJ_DATA *arrow;
	int type;

	push_call("spell_ice_arrow(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((type = get_flag(target_name, bow_types)) == -1)
	{
		ch_printf(ch, "Create what kind of arrow, %s?\n\r", give_flags(bow_types));
		pop_call();
		return;
	}
	arrow = create_object(get_obj_index(OBJ_VNUM_ICE_ARROW), 0);

	arrow->value[0] = type;
	arrow->value[1] = level;
	arrow->value[2] = URANGE(10, level/4, 20);
	arrow->value[3] = 5;
	arrow->level    = level / 2;

	SET_BIT(arrow->extra_flags, ITEM_MODIFIED);

	act("$p of frigid, dangerous beauty takes shape in your hand.", ch, arrow, NULL, TO_CHAR);
	act("$p of frigid, dangerous beauty takes shape in $n's hand.", ch, arrow, NULL, TO_ROOM);

	if (ch->carry_number < can_carry_n(ch) && ch->carry_weight < can_carry_w(ch))
	{
		obj_to_char(arrow, ch);
	}
	else
	{	
		obj_to_room(arrow, ch->in_room->vnum);
	}
	pop_call();
	return;
}

DO_SPELL(spell_cure_blindness)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;

	push_call("spell_cure_blindness(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!is_affected(victim, gsn_blindness))
	{
		if (!is_affected(victim, gsn_gouge))
		{
			if (!is_affected(victim, gsn_flash_powder))
			{
				send_to_char( "They aren't blinded.\n\r", ch );
	
				pop_call();
				return;
			}
		}
	}

	affect_strip( victim, gsn_blindness );
	affect_strip( victim, gsn_gouge );
	affect_strip( victim, gsn_flash_powder );

	send_to_char( "Your vision returns!\n\r", victim );

	if (ch != victim)
	{
		send_to_char( "They are no longer blinded.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_cure_light)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;

	push_call("spell_cure_light(%p,%p,%p,%p)",sn,level,ch,vo);

	heal = dice(1, 15) + level / 2;

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );

	send_to_char( "Your light wounds mend and your pain ebbs slightly.\n\r", victim );

	if (ch != victim)
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_cure_serious)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;

	push_call("spell_cure_serious(%p,%p,%p,%p)",sn,level,ch,vo);

	heal = dice(1, 25) + level * 2 / 3 ;

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );

	send_to_char( "Your serious wounds mend and your pain ebbs away.\n\r", victim );

	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_cure_critical)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;

	push_call("spell_cure_critical(%p,%p,%p,%p)",sn,level,ch,vo);

	heal = dice(1, 50) + level;

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );

	send_to_char( "Your critical wounds close and your pain ebbs away.\n\r", victim );
	affect_strip(victim,gsn_critical_hit);

	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_cure_poison)
{
	CHAR_DATA	*victim = (CHAR_DATA *) vo;
	bool		cured   = FALSE;

	push_call("spell_cure_poison(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, gsn_poison ) )
	{
		affect_strip( victim, gsn_poison );
		cured = TRUE;
	}

	if (victim->poison != NULL)
	{
		POISON_DATA *npd, *pd;
		cured = TRUE;

		pd = victim->poison;
		victim->poison = NULL;

		while (pd != NULL)
		{
			npd = pd->next;
			FREEMEM( pd );
			pd = npd;
		}
	}

	if ( cured )
	{
		act( "$N looks better.", ch, NULL, victim, TO_CHAR );
		act( "$N looks better.", ch, NULL, victim, TO_ROOM );
		send_to_char( "A warm feeling runs through your body.\n\r", victim );
	}
	else
	{
		act( "$N does not seem to be poisoned.", ch, NULL, victim, TO_CHAR );
	}
	pop_call();
	return;
}

DO_SPELL(spell_curse)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_curse(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_CURSE) )
	{
		send_to_char( "They are already cursed.\n\r", ch );
		pop_call();
		return;
	}

	if ( saves_spell( level, ch, victim ) )
	{
		send_to_char( "Your curse did not strike them.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/15;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_CURSE;

	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = UMAX(level/20, 3);
	affect_to_char( victim, &af );

	af.location  = APPLY_HITROLL;
	af.modifier  = UMIN(level/-10, -6);
	affect_to_char( victim, &af );

	send_to_char( "You feel unclean.\n\r", victim );

	if ( ch != victim )
	{
		send_to_char( "Your foe is now cursed.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_detect_evil)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_detect_evil(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	send_to_char( "Traces of red outline all evil in plain sight.\n\r", victim );

	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_detect_hidden)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_detect_hidden(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_DETECT_HIDDEN) || IS_AFFECTED(victim, AFF_TRUESIGHT))
	{
		send_to_char( "You are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_DETECT_HIDDEN;
	affect_to_char( victim, &af );

	send_to_char( "Your senses are heightened to those of an animal.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_detect_invis)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_detect_invis(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_DETECT_INVIS) || IS_AFFECTED(victim, AFF_TRUESIGHT))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_DETECT_INVIS;
	affect_to_char( victim, &af );

	send_to_char( "Your eyes fixate as they gain the ability to see the unseen.\n\r", victim );

	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_detect_poison)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;

	push_call("spell_detect_poison(%p,%p,%p,%p)",sn,level,ch,vo);

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

/*
	Changed dispel spells slightly, you now damage the victim and make
	it gain or lose alignment, when the victim hits neutral alignment
	their gear will be checked for zappers - Scandum 01/04/2002
*/

DO_SPELL(spell_dispel_evil)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_dispel_evil(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!IS_NPC(ch) && IS_EVIL(ch))
	{
		victim = ch;
  	}

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

	dam = number_range(level, level * 5);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}

	damage( ch, victim, dam, sn );

	victim->alignment += 5;

	if (IS_NEUTRAL(victim))
	{
		check_zap(victim, TRUE);
	}
	pop_call();
	return;
}

DO_SPELL(spell_dispel_good)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_dispel_good(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!IS_NPC(ch) && IS_GOOD(ch))
	{
		victim = ch;
  	}

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

	dam = number_range (level, level * 5);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}

	damage( ch, victim, dam, sn );

	victim->alignment -= 5;

	if (IS_NEUTRAL(victim))
	{
		check_zap(victim, TRUE);
	}
	pop_call();
	return;
}

DO_SPELL(spell_dispel_undead)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_dispel_undead(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_NPC(victim) && !IS_SET(victim->act , ACT_UNDEAD))
	{
		if (!rspec_req(victim, RSPEC_UNDEAD))
		{
			act( "$N is not affected.", ch, NULL, victim, TO_CHAR);
			pop_call();
			return;
		}
	}

	dam = number_range(level*3, level*9);

	if ( saves_spell( level/2, ch, victim ) )
	{
		dam /= 3;
	}
	damage( ch, victim, dam, sn );
	pop_call();
	return;
}

DO_SPELL(spell_dispel_magic)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf, *paf_prev;
	int paf_type;

	push_call("spell_dispel_magic(%p,%p,%p,%p)",sn,level,ch,vo);

	if (target == TAR_CHAR_DEFENSIVE)
	{
		if (saves_spell(level, ch, victim))
		{
			send_to_char( "You failed.\n\r", ch );
			pop_call();
			return;
		}

		for (paf_type = 0, paf = victim->last_affect ; paf ; paf = paf_prev)
		{
			paf_prev = paf->prev;

			if (!is_spell(paf->type))
			{
				continue;
			}

			switch (paf->bitvector)
			{
				case AFF2_POSSESS:
				case AFF_CHARM:
					continue;
			}

			if (paf_type && paf->type != paf_type)
			{
				continue;
			}

			if (paf_type == 0 && paf->duration >= 0)
			{
				if (skill_table[paf->type].msg_off)
				{
					act(skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
				}
			}
			paf_type = paf->type;
			affect_from_char(victim, paf);
		}

		if (paf_type == 0)
		{
			send_to_char( "Nothing appears to happen.\n\r", ch );
		}
		else if (victim != ch)
		{
			send_to_char( "Their magic spells seem to vanish slowly.\n\r", ch );
		}
	}
	else
	{
		for (paf_type = 0, paf = obj->last_affect ; paf ; paf = paf_prev)
		{
			paf_prev = paf->prev;

			if (!is_spell(paf->type))
			{
				continue;
			}

			if (paf_type && paf->type != paf_type)
			{
				continue;
			}

			if (paf_type == 0 && paf->duration >= 0)
			{
				if (skill_table[paf->type].msg_obj_off)
				{
					act(skill_table[paf->type].msg_obj_off, ch, obj, NULL, TO_CHAR);
				}
			}
			paf_type = paf->type;
			affect_from_obj(obj, paf);
		}

		if (paf_type == 0)
		{
			send_to_char( "Nothing appears to happen.\n\r", ch );
		}
	}
	pop_call();
	return;
}

DO_SPELL(spell_earthquake)
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	EXIT_DATA *pexit;
	int door, temp_vnum;

	push_call("spell_earthquake(%p,%p,%p,%p)",sn,level,ch,vo);

	/*
		no earthquakes in the air
	*/

	if (ch->in_room->sector_type == SECT_AIR)
	{
		send_to_char("The earth trembles far beneath you.\n\r",ch);
		pop_call();
		return;
	}

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

	temp_vnum = ch->in_room->vnum;

	for (door = 0 ; door <= 5 ; door++)
	{
		if ((pexit = get_exit(temp_vnum, door)) && pexit->to_room != temp_vnum)
		{
			ch->in_room = room_index[pexit->to_room];
			act("The earth trembles and shivers.", ch, NULL, NULL, TO_ROOM );
		}
	}
	ch->in_room = room_index[temp_vnum];

	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;

		if (CAN_FLY(vch))
		{
			continue;
		}
		if (!can_mass_cast(ch, vch))
		{
			continue;
		}
		damage( ch, vch, level + dice(2, 8), sn );
	}
	pop_call();
	return;
}

DO_SPELL(spell_tremor)
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	EXIT_DATA *pexit;
	int door, temp_vnum;

	push_call("spell_tremor(%p,%p,%p,%p)",sn,level,ch,vo);

	if (ch->in_room->sector_type == SECT_AIR)
	{
		send_to_char("The earth tremors far beneath you.\n\r",ch);
		pop_call();
		return;
	}

	temp_vnum = ch->in_room->vnum;

	for (door = 0 ; door <= 5 ; door++)
	{
		if ((pexit = get_exit(temp_vnum, door)) && pexit->to_room != temp_vnum)
		{
			ch->in_room = room_index[pexit->to_room];
			act("You hear a loud wrenching noise from the ground.", ch, NULL, NULL, TO_ROOM );
		}
	}
	ch->in_room = room_index[temp_vnum];

	send_to_char( "The earth tremors beneath your feet!\n\r", ch );
	act( "$n makes the earth shake.", ch, NULL, NULL, TO_ROOM );

	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;

		if (CAN_FLY(vch))
		{
			continue;
		}
		if (!can_mass_cast(ch, vch))
		{
			continue;
		}
		if (number_bits(3) == 0)
		{
			vch->position = POS_RESTING;
		}
		damage(ch, vch, number_range(level * 2, level * 3) + dice(5, 20), sn);
	}
	pop_call();
	return;
}

DO_SPELL(spell_enchant_weapon)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_enchant_weapon(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!IS_NPC(ch) && multi(ch, sn) == -1)
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (obj->item_type != ITEM_WEAPON || IS_OBJ_STAT(obj, ITEM_MAGIC) || obj->first_affect != NULL)
	{
		send_to_char( "That object cannot be enchanted.\n\r", ch);
		pop_call();
		return;
	}

	SET_BIT(obj->extra_flags, ITEM_MODIFIED);
	SET_BIT(obj->extra_flags, ITEM_MAGIC);

	af.type		= sn;
	af.duration	= -1;
	af.bittype	= AFFECT_TO_NONE;
	af.bitvector	= 0;

	af.location	= APPLY_HITROLL;
	af.modifier	= level / 5;

	affect_to_obj(obj, &af);

	af.location	= APPLY_DAMROLL;
	af.modifier	= level / 10;

	affect_to_obj(obj, &af);

	obj->level += level/3;


	if (IS_GOOD(ch))
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
		act("$p glows yellow.", ch, obj, NULL, TO_ROOM);
	}
	else if (IS_EVIL(ch))
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
		act("$p glows red.", ch, obj, NULL, TO_ROOM);
	}
	else
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
		SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
		act("$p glows blue.", ch, obj, NULL, TO_ROOM);
	}

	act("$p has been enchanted.", ch, obj, NULL, TO_CHAR);
	pop_call();
	return;
}

DO_SPELL(spell_energy_bolt)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_energy_bolt(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = 10 + number_range(level, level*2);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_energy_drain)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_energy_drain(%p,%p,%p,%p)",sn,level,ch,vo);

	if (saves_spell(5 * level / 4, ch, victim))
	{
		switch(number_range(1,3))
		{

			case 1: act( "$N shrugs off your deathly embrace!", ch, NULL, victim, TO_CHAR); break;
			case 2: act( "$N flinches but is unharmed.", ch, NULL, victim, TO_CHAR); break;
			case 3: act( "$N moans softly from your spine chilling spell, but is otherwise unharmed.", ch, NULL, victim, TO_CHAR); break;
		}
		pop_call();
		return;
	}

	if (!IS_NPC(victim))
	{
		gain_exp(victim, 0 - dice(level, 5));
	}
	dam			= number_range(level * 2, level * 4) + 50;
	ch->hit		= UMIN(ch->hit + dam / 6, ch->max_hit);
	victim->move	= UMAX(0, victim->move - number_fuzzy(dam) / 3);
	victim->mana	= UMAX(0, victim->mana - number_fuzzy(dam) / 3);

	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_fireball)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_fireball(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range( level*3 , level*5);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_flamestrike)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_flamestrike(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level, level+150);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_faerie_fire)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_faerie_fire(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, gsn_faerie_fire))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_AC;
	af.modifier  = 2 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	send_to_char( "You are surrounded by a pink outline.\n\r", victim );
	act( "$n is surrounded by a pink outline.", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_faerie_fog)
{
	CHAR_DATA *ich;

	push_call("spell_faerie_fog(%p,%p,%p,%p)",sn,level,ch,vo);

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

	for ( ich = ch->in_room->first_person; ich != NULL; ich = ich->next_in_room )
	{
		if ( !IS_NPC(ich) && IS_SET(ich->act, PLR_WIZINVIS) )
			continue;

		if ( !IS_NPC(ich) && IS_SET(ich->act, PLR_WIZCLOAK) )
			continue;

		if( IS_NPC(ich) && IS_AFFECTED(ich, AFF_ETHEREAL) )
			continue;

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

		affect_strip ( ich, gsn_invis					);
		affect_strip ( ich, gsn_sneak					);
		affect_strip ( ich, gsn_stealth				);
		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_by, AFF_STEALTH		);
		REMOVE_BIT   ( ich->affected_by, AFF_IMP_INVISIBLE);
		act( "$n is revealed!", ich, NULL, NULL, TO_ROOM );
		send_to_char( "You are revealed!\n\r", ich );
	}
	pop_call();
	return;
}

DO_SPELL(spell_fly)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_fly(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF2_EARTHBIND))
	{
		send_to_char("They are bound to the earth.\n\r", ch);
		pop_call();
		return;
	}

	if (CAN_FLY(victim))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level + 3;
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_FLYING;
	affect_to_char( victim, &af );
	send_to_char( "Your feet rise off the ground.\n\r", victim );
	act( "$n's feet rise off the ground.", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_gate)
{
	CHAR_DATA *victim;
	OBJ_DATA *gate;

	push_call("spell_gate(%p,%p,%p,%p)",sn,level,ch,vo);

	if (target_name[0] == '\0')
	{
		send_to_char("Whom would you want to gate to?\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_char_area(ch, target_name)) == NULL)
	{
		send_to_char("There is none named like that.\n\r", ch);
		pop_call();
		return;
	}

	if  (IS_SET(ch->in_room->room_flags, ROOM_IS_CASTLE)
	||  (IS_NPC(victim) && level / 3 < victim->level)
	|| (!IS_NPC(victim) && level - 3 < victim->level))
	{
		send_to_char( "They are protected from your power.\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(victim) && is_affected(victim, gsn_anti_magic_shell))
	{
		act("The flows of magic shatter against a shell surrounding $N.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (victim == ch
	|| victim->in_room == NULL
	|| 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(ch->in_room->room_flags, ROOM_NO_RECALL)
	|| victim->in_room->sector_type == SECT_ETHEREAL
	|| victim->in_room->sector_type == SECT_ASTRAL
	|| ch->in_room->sector_type == SECT_ETHEREAL
	|| ch->in_room->sector_type == SECT_ASTRAL
	|| IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
	|| IS_SET(ch->in_room->area->flags, AFLAG_NOSUMMON)
	|| victim->level > UMIN(ch->level-3, level - 3)
	|| find_keeper(victim) != NULL)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	if (ch->in_room == victim->in_room)
	{
		send_to_char("You are already there.\n\r",ch);
		pop_call();
		return;
	}

	if (saves_spell(level,ch,victim))
	{
		send_to_char("You failed to envision your victim.\n\r", ch);
		pop_call();
		return;
	}

	gate = create_object(get_obj_index(OBJ_VNUM_GATE), 0);

	if (!gate)
	{
		ch_printf(ch,"You try to create a gate, but it does not seem possible somehow.\n\r");
		pop_call();
		return;
	}
	gate->value[3] = victim->in_room->vnum;

	obj_to_room(gate, ch->in_room->vnum);

	act( "$p opens before you.", ch, gate, NULL, TO_CHAR);
	act( "$p opens before $n.",  ch, gate, NULL, TO_ROOM);

	do_enter(ch, "i23");
	obj_from_room(gate);
	junk_obj(gate);
	pop_call();
	return;
}

/*
 * Spell for mega1.are from Glop/Erkenbrand.
 */

DO_SPELL(spell_general_purpose)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_general_purpose(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range( 25, 100 );
	if ( saves_spell( level, ch, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	pop_call();
	return;
}

DO_SPELL(spell_giant_strength)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_giant_strength(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_STR;
	af.modifier  = 1 + (level >= 18) + (level >= 25);
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	send_to_char( "You feel the strength of a giant.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_harm)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_harm(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = 100 + number_range(0, 4) * 50;

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}

	damage( ch, victim, number_fuzzy(dam), sn );

	pop_call();
	return;
}

DO_SPELL(spell_heal)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;

	push_call("spell_heal(%p,%p,%p,%p)",sn,level,ch,vo);

	victim->hit = UMIN( victim->hit + 100, victim->max_hit );
	update_pos( victim );
	send_to_char( "A warm feeling fills your body.\n\r", victim );
	affect_strip(victim,gsn_critical_hit);
	affect_strip(victim,631); /* HALLUCINATE */
	if ( ch != victim )
	{
		send_to_char( "Healing powers at work.\n\r", ch );
	}
	pop_call();
	return;
}

/*
 * Spell for mega1.are from Glop/Erkenbrand.
 */

DO_SPELL(spell_high_explosive)
{

	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_high_explosive(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range( 30, 120 );
	if ( saves_spell( level, ch, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	pop_call();
	return;
}

DO_SPELL(spell_identify)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	char buf[MAX_STRING_LENGTH];
	AFFECT_DATA *paf;

	push_call("spell_identify(%p,%p,%p,%p)",sn,level,ch,vo);

	ch_printf(ch, "%s is type %s, extra flags %s.\n\rWeight is %d, value is %d, level is %d.\n\r",
		capitalize(obj->short_descr),
		item_type_name(obj),
		flag_string(obj->extra_flags, o_flags),
		get_obj_weight(obj),
		obj->cost,
		obj->level);

	switch ( obj->item_type )
	{
		case ITEM_SCROLL:
		case ITEM_POTION:
		case ITEM_PILL:
			sprintf(buf, "Level %d spells of:", obj->value[0]);

			if (obj->value[1] > 0 && obj->value[1] < MAX_SKILL)
			{
				cat_sprintf(buf, " '%s'", skill_table[obj->value[1]].name);
			}

			if (obj->value[2] > 0 && obj->value[2] < MAX_SKILL)
			{
				cat_sprintf(buf, " '%s'", skill_table[obj->value[2]].name);
			}

			if (obj->value[3] > 0 && obj->value[3] < MAX_SKILL)
			{
				cat_sprintf(buf, " '%s'", skill_table[obj->value[3]].name);
			}
			ch_printf(ch, "%s\n\r", buf);
			break;

		case ITEM_WAND:
		case ITEM_STAFF:
			sprintf(buf, "Has %d/%d charges of level %d",
				obj->value[2],
				obj->value[1],
				obj->value[0]);

			if (obj->value[3] >= 0 && obj->value[3] < MAX_SKILL)
			{
				cat_sprintf(buf, " '%s'", skill_table[obj->value[3]].name);
			}
			ch_printf(ch, "%s\n\r", buf);
			break;

		case ITEM_WEAPON:
			switch (obj->value[0])
			{
				case WEAPON_TYPE_WEAPON:
					ch_printf(ch, "Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_SWORD:
					ch_printf(ch, "This weapon is a sword. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_DAGGER:
					ch_printf(ch, "This weapon is a dagger. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_AXE:
					ch_printf(ch, "This weapon is an axe. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_MACE:
					ch_printf(ch, "This weapon is a mace. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_STAFF:
					ch_printf(ch, "This weapon is a staff. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_WHIP:
					ch_printf(ch, "This weapon is a whip. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_FLAIL:
					ch_printf(ch, "This weapon is a flail. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_SPEAR:
					ch_printf(ch, "This weapon is a spear. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_CLAW:
					ch_printf(ch, "This weapon is a claw. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_SHORTBOW:
					ch_printf(ch, "This weapon is a short bow. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_LONGBOW:
					ch_printf(ch, "This weapon is a long bow. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_CROSSBOW:
					ch_printf(ch, "This weapon is a cross bow. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				case WEAPON_TYPE_BLOWPIPE:
					ch_printf(ch, "This weapon is a blow pipe. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
				default:
					ch_printf(ch, "This weapon is faulty. Talk to Demise. Damage is %dd%d.\n\r", obj->value[1], obj->value[2]);
					break;
			}
			break;

		case ITEM_ARMOR:
			ch_printf(ch, "Armor class is %d.\n\r", obj->value[0] );
			break;

		case ITEM_AMMO:
			switch (obj->value[0])
			{
				case WEAPON_TYPE_SHORTBOW:
					ch_printf(ch, "Ammo type for short bows, Damage is %d, Speed is %d, Range is %d.\n\r",
						obj->value[1], obj->value[2], obj->value[3]);
					break;
				case WEAPON_TYPE_LONGBOW:
					ch_printf(ch, "Ammo type for long bows, Damage is %d, Speed is %d, Range is %d.\n\r",
						obj->value[1], obj->value[2], obj->value[3]);
					break;
				case WEAPON_TYPE_CROSSBOW:
					ch_printf(ch, "Ammo type for cross bows, Damage is %d, Speed is %d, Range is %d.\n\r",
						obj->value[1], obj->value[2], obj->value[3]);
					break;
				case WEAPON_TYPE_BLOWPIPE:
					ch_printf(ch, "Ammo type for blow pipes, Damage is %d, Speed is %d, Range is %d.\n\r",
						obj->value[1], obj->value[2], obj->value[3]);
					break;
				default:
					ch_printf(ch, "Ammo type is faulty. Talk to Demise. Damage is %d, Speed is %d, Range is %d.\n\r",
						obj->value[1], obj->value[2], obj->value[3]);
					break;
			}
			break;
		case ITEM_CONTAINER:
			ch_printf(ch, "Capacity is %d weight and %d items.\n\r", obj->value[0], obj->value[3] ? obj->value[3] : MAX_OBJECTS_IN_CONTAINER);
			break;
	}

	for (paf = obj->pIndexData->first_affect ; paf ; paf = paf->next)
	{
		switch (paf->location)
		{
			case APPLY_NONE:
				break;

			default:
				ch_printf(ch, "Affects %s by %d.\n\r", affect_loc_name(paf->location), paf->modifier);
				break;
		}
		switch (paf->bittype)
		{
			case AFFECT_TO_NONE:
				break;

			case AFFECT_TO_CHAR:
				ch_printf(ch, "Affects wearer with %s.\n\r", affect_bit_name(paf->bitvector));
				break;

			case AFFECT_TO_OBJ:
				ch_printf(ch, "Affects object with %s.\n\r", flag_string(paf->bitvector, o_flags));
				break;
		}
	}

	for (paf = obj->first_affect ; paf != NULL ; paf = paf->next)
	{
		switch (paf->location)
		{
			case APPLY_NONE:
				break;

			default:
				ch_printf(ch, "Affects %s by %d.\n\r", affect_loc_name(paf->location), paf->modifier);
				break;
		}
		switch (paf->bittype)
		{
			case AFFECT_TO_NONE:
				break;

			case AFFECT_TO_CHAR:
				ch_printf(ch, "Affects wearer with %s.\n\r", affect_bit_name(paf->bitvector));
				break;

			case AFFECT_TO_OBJ:
				ch_printf(ch, "Affects object with %s.\n\r", flag_string(paf->bitvector, o_flags));
				break;
		}
	}
	sprintf(buf, "Wear locations:");

	if (!IS_SET(obj->wear_flags, ITEM_TAKE))
	{
		strcat( buf, " Cannot take");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_FINGER))
	{
		strcat( buf, " Fingers");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_NECK))
	{
		strcat( buf, " Neck");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_BODY))
	{
		strcat( buf, " Body");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_HEAD))
	{
		strcat( buf, " Head");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_LEGS))
	{
		strcat( buf, " Legs");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_FEET))
	{
		strcat( buf, " Feet");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_HANDS))
	{
		strcat( buf, " Hands");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_ARMS))
	{
		strcat( buf, " Arms");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
	{
		strcat( buf, " Shield");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_ABOUT))
	{
		strcat( buf, " About");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_WAIST))
	{
		strcat( buf, " Waist");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_WRIST))
	{
		strcat( buf, " Wrist");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_WIELD))
	{
		strcat( buf, " Wield");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_HOLD))
	{
		strcat( buf, " Hold");
	}
	if (IS_SET(obj->wear_flags, ITEM_WEAR_HEART))
	{
		strcat( buf, " Heart");
	}
	if (strlen(buf) < 17)
	{
		strcat( buf, " Carry only");
	}
	ch_printf(ch, "%s.\n\r", buf);

	pop_call();
	return;
}

DO_SPELL(spell_infravision)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_infravision(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_INFRARED) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	act( "$n's eyes glow red.", ch, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = 2 * level;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_INFRARED;
	affect_to_char( victim, &af );
	send_to_char( "Your eyes glow red.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_enhanced_heal)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_enhanced_heal(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF2_ENHANCED_HEAL) )
	{
		send_to_char("They are already healing easily.\n\r", ch);
		pop_call();
		return;
	}

	act( "$n heals easily.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_ENHANCED_HEAL;
	affect_to_char( victim, &af );
	send_to_char( "You heal easily.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_enhanced_revive)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_enhanced_revive(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF2_ENHANCED_REVIVE) )
	{
		send_to_char("They are already reviving easily.\n\r", ch);
		pop_call();
		return;
      }

	act( "$n revives easily.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_ENHANCED_REVIVE;
	affect_to_char( victim, &af );
	send_to_char( "You revive easily.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_enhanced_rest)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_enhanced_rest(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF2_ENHANCED_REST) )
	{
		send_to_char("They are already resting easily.\n\r", ch);
		pop_call();
		return;
	}

	act( "$n rests easily.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_ENHANCED_REST;
	affect_to_char( victim, &af );
	send_to_char( "You rest easily.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_remove_fear)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_remove_fear(%p,%p,%p,%p)",sn,level,ch,vo);

	if (saves_spell(level, ch, victim))
	{
		send_to_char( "They are not made fearless.\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_NPC(victim))
	{
		if (is_affected(victim, sn))
		{
			send_to_char("They are already fearless.\n\r", ch);
			pop_call();
			return;
		}

		af.type		= sn;
		af.duration	= level / 3;
		af.bittype	= AFFECT_TO_NONE;
		af.bitvector	= 0;
		af.location	= APPLY_NONE;
		af.modifier	= 0;

		affect_to_char(victim, &af);

		affect_strip(victim, gsn_fear);

		victim->pcdata->wimpy = 0;
	}
	else
	{
		if (!IS_SET(victim->act, ACT_WIMPY))
		{
			send_to_char( "They are already fearless.\n\r", ch );
			pop_call();
			return;
		}
		REMOVE_BIT(victim->act, ACT_WIMPY);
	}
	act("You become fearless!", victim, NULL, NULL, TO_CHAR );
	act("$n becomes fearless!", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_fear)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_fear(%p,%p,%p,%p)",sn,level,ch,vo);

	if (saves_spell(level, ch, victim))
	{
		send_to_char( "They are not made frightened.\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_NPC(victim))
	{
		if (is_affected(victim, sn))
		{
			send_to_char("They are already frightened.\n\r", ch);
			pop_call();
			return;
		}

		af.type		= sn;
		af.duration	= level / 3;
		af.bittype	= AFFECT_TO_NONE;
		af.bitvector	= 0;
		af.location	= APPLY_NONE;
		af.modifier	= 0;

		affect_to_char(victim, &af);

		affect_strip(victim, gsn_remove_fear);

		victim->pcdata->wimpy = victim->max_hit / 2;
	}
	else
	{
		if (IS_SET(victim->act, ACT_WIMPY))
		{
			send_to_char( "They are already frightened.\n\r", ch );
			pop_call();
			return;
		}
		SET_BIT(victim->act, ACT_WIMPY);
	}
	act("You become filled with fear!", victim, NULL, NULL, TO_CHAR );
	act("$n becomes filled with fear!", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_haste)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_haste(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_HASTE))
	{
		send_to_char("They are already fast.\n\r", ch);
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_DEX;

	if (which_god(victim) != GOD_MANWE)
	{
		af.duration = URANGE(6, level / 8, 24);
		af.modifier = 1 + (level > 49) + (level > 99);
	}
	else
	{
		af.duration = URANGE(12, level / 4, 48);
		af.modifier = 1 + (level > 24) + (level > 49) + (level > 74) + (level > 99) + (level > 124);
	}
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_HASTE;
	affect_to_char(victim, &af);

	send_to_char("You speed up.\n\r", victim);
	act("$n speeds up.", victim, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_invis)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_invis(%p,%p,%p,%p)",sn,level,ch,vo);

	if (target == TAR_CHAR_DEFENSIVE)
	{
		if (IS_AFFECTED(victim, AFF_INVISIBLE) || IS_AFFECTED(victim, AFF_IMP_INVISIBLE))
		{
			send_to_char("They are already invisible.\n\r", ch);
			pop_call();
			return;
		}

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

		af.type      = sn;
		af.duration  = level;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_INVISIBLE;
		affect_to_char( victim, &af );
	}
	else if (target == TAR_OBJ_INV)
	{
		if (IS_SET(obj->extra_flags, ITEM_INVIS))
		{
			act("$p is already invisible.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}

		af.type      = sn;
		af.duration  = level;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_OBJ;
		af.bitvector = ITEM_INVIS;

		affect_to_obj(obj, &af );

		SET_BIT(obj->extra_flags, ITEM_MODIFIED);

		act("$p fades out of existance.", ch, obj, NULL, TO_CHAR);
	}
	pop_call();
	return;
}

DO_SPELL(spell_invis_obj)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;

	push_call("spell_invis_obj(%p,%p,%p,%p)",sn,level,ch,vo);

	if (number_fuzzy(obj->level) > level)
	{
		send_to_char( "You failed.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_SET(obj->extra_flags, ITEM_INVIS))
	{
		send_to_char( "It is already invisible.\n\r", ch);
		pop_call();
		return;
	}

	SET_BIT(obj->extra_flags, ITEM_INVIS);
	SET_BIT(obj->extra_flags, ITEM_MODIFIED);

	send_to_char( "Ok.\n\r", ch );
	pop_call();
	return;
}

DO_SPELL(spell_tongues)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_tongues(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_TONGUES))
	{
		send_to_char( "That person is already speaking in tongues.\n\r", ch);
		pop_call();
		return;
	}

	act( "$n starts speaking in tongues.", victim, NULL, NULL, TO_ROOM);
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_TONGUES;
	affect_to_char( victim, &af);
	send_to_char( "You start speaking in tongues.\n\r", victim);
	if(ch!=victim)
	{
		send_to_char( "Ok.\n\r", ch);
	}
	pop_call();
	return;
}

DO_SPELL(spell_understand)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_understand(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_UNDERSTAND))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	act( "$n starts understanding everyone.", victim, NULL, NULL, TO_ROOM);
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_UNDERSTAND;
	affect_to_char( victim, &af);
	send_to_char( "You start understanding everyone.\n\r", victim);
	if(ch!=victim)
	{
		send_to_char( "Ok.\n\r", ch);
	}
	pop_call();
	return;
}

DO_SPELL(spell_petrifying_touch)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_petrifying_touch(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level+30, level+110);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	else if (number_bits(1) == 0)
	{
		AFFECT_DATA af;

		af.type      = sn;
		af.duration  = 1;
		if (!IS_NPC(victim))
		{
			af.location = APPLY_DEX;
			af.modifier = -1;
		}
		else
		{
			af.location = APPLY_AC;
			af.modifier = 2;
		}
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;
		affect_join( victim, &af );
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_locate_object)
{
	OBJ_DATA *obj;
	OBJ_DATA *in_obj;
	int count;

	push_call("spell_locate_object(%p,%p,%p,%p)",sn,level,ch,vo);

	if (*target_name == '\0')
	{
		send_to_char( "Nothing like that in hell, earth, or heaven.\n\r", ch );
		pop_call();
		return;
	}

	if (strlen(target_name) > 20)
	{
		target_name[20] = '\0';
	}

	count = 0;

	for (obj = mud->f_obj ; obj ; obj = obj->next)
	{
		if (obj->level > level || !is_multi_name_list_short(target_name, short_to_name(obj->short_descr, 1)) || !can_see_obj(ch, obj) )
		{
			continue;
		}

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

		if (in_obj->carried_by && !can_see_world(ch, in_obj->carried_by))
		{
			continue;
		}

		count++;

		if (in_obj->carried_by != NULL)
		{
			ch_printf(ch, "%s%s is carried by %s.\n\r", get_color_string(ch, COLOR_TEXT, VT102_DIM), capitalize(obj->short_descr), PERS(in_obj->carried_by, ch));
		}
		else
		{
			ch_printf(ch, "%s%s is in %s.\n\r", get_color_string(ch, COLOR_TEXT, VT102_DIM), capitalize(obj->short_descr), in_obj->in_room == NULL ? "somewhere" : in_obj->in_room->name);
		}
		if (count > UMAX(20, 10 + level / 10))
		{
			break;
		}
	}

	if (count == 0)
	{
		send_to_char( "Nothing like that in hell, earth, or heaven.\n\r", ch );
	}

	pop_call();
	return;
}

DO_SPELL(spell_magic_missile)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_magic_missile(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level / 2 + 40, level / 2 + 60);

	if (!IS_AFFECTED(ch, AFF2_QUICKEN))
	{
		switch (level / 25)
		{
			case 0:	wait_state(ch, 1 + skill_table[sn].beats * 3);	break;
			case 1:	wait_state(ch, 1 + skill_table[sn].beats * 2);	break;
			default:	wait_state(ch, 1 + skill_table[sn].beats * 1);	break;
		}
	}

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}

	damage( ch, victim, dam, sn );
	pop_call();
	return;
}

DO_SPELL(spell_mass_invis)
{
	AFFECT_DATA af;
	CHAR_DATA *gch;

	push_call("spell_mass_invis(%p,%p,%p,%p)",sn,level,ch,vo);

	for (gch = ch->in_room->first_person ; gch ; gch = gch->next_in_room)
	{
		if (!is_same_group(gch, ch))
		{
			continue;
		}
		if (IS_AFFECTED(gch, AFF_INVISIBLE) || IS_AFFECTED(gch, AFF_IMP_INVISIBLE))
		{
			continue;
		}

		act("$n slowly fades out of existence.", gch, NULL, NULL, TO_ROOM);
		act("You slowly fade out of existence.", gch, NULL, NULL, TO_CHAR);
		af.type      = gsn_invis;
		af.duration  = 24;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_INVISIBLE;
		affect_to_char( gch, &af );
	}
	send_to_char( "Ok.\n\r", ch );

	pop_call();
	return;
}

DO_SPELL(spell_null)
{
	push_call("spell_null(%p,%p,%p,%p)",sn,level,ch,vo);

	send_to_char( "That's not a spell!\n\r", ch );
	pop_call();
	return;
}

DO_SPELL(spell_pass_door)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_pass_door(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_PASS_DOOR) || rspec_req(victim,RSPEC_PASS_DOOR))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_PASS_DOOR;
	affect_to_char( victim, &af );
	act( "$n turns translucent.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You turn translucent.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_poison)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_poison(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_POISON) )
	{
		send_to_char( "They are already poisoned.\n\r", ch );
		pop_call();
		return;
	}

	if ( saves_spell( level, ch, victim ) )
	{
		send_to_char( "They turn slightly green but it passes.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		af.type      = sn;
		af.duration  = level;
		af.location  = APPLY_AC;
		af.modifier  = level;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_POISON;
	}
	else
	{
		af.type      = sn;
		af.duration  = level/4;
		af.location  = APPLY_STR;
		af.modifier  = -2;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_POISON;
	}
	affect_to_char(victim, &af );
	send_to_char( "You feel poison coursing through your vains.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "They now feel your poison.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_mage_blast)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_mage_blast(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, gsn_mage_blast))
	{
		send_to_char( "Your blast was ineffective.\n\r", ch );
		pop_call();
		return;
	}
	if (saves_spell(level, ch, victim))
	{
		af.type      = sn;
		af.duration  = 1;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;
		affect_to_char( victim, &af );
		send_to_char( "Your blast was repelled.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/20;
	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = level/8;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	send_to_char( "Your magic aura has been weakened.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "You blast through their magical defenses.\n\r", ch );
	}
	pop_call();
	return;
}

/*
	Checked spells till here - Scandum
*/

DO_SPELL(spell_protection_fe)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_protection_fe(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_PROTECT_EVIL) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/4;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_PROTECT_EVIL;
	affect_to_char( victim, &af );
	send_to_char( "You feel protected from evil.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Protection has been applied from evil.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_protection_fg)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_protection_fg(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( IS_AFFECTED(victim, AFF_PROTECT_GOOD) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/5;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_PROTECT_GOOD;
	affect_to_char( victim, &af );
	send_to_char( "You feel protected from good.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Protection from good is now working.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_refresh)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;

	push_call("spell_refresh(%p,%p,%p,%p)",sn,level,ch,vo);

	victim->move = UMIN( victim->move + level, victim->max_move );
	send_to_char( "You feel less tired.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Movement is now restoring.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_remove_curse)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj;
	char buf[MAX_STRING_LENGTH];

	push_call("spell_remove_curse(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, gsn_curse))
	{
		affect_strip( victim, gsn_curse );
		send_to_char( "You feel better.\n\r", victim );
		if (ch != victim)
		{
			send_to_char( "Your spell has taken the curse away.\n\r", ch );
		}
		pop_call();
		return;
	}
	for(obj=victim->first_carrying; obj!=NULL ; obj=obj->next_content)
	if((!IS_SET(obj->extra_flags, ITEM_INVENTORY)) &&
		(IS_SET(obj->extra_flags, ITEM_NODROP) ||
		IS_SET(obj->extra_flags, ITEM_NOREMOVE)))
	{
		REMOVE_BIT( obj->extra_flags, ITEM_NOREMOVE);
		REMOVE_BIT( obj->extra_flags, ITEM_NODROP);
		if( victim!=ch)
			send_to_char( "Ok.\n\r", ch);
		sprintf( buf, "%s is no longer cursed.\n\r", obj->short_descr);
		if( buf[0]>='a' && buf[0]<='z')
			buf[0]-=('a'-'A');
		send_to_char( buf, victim);
		pop_call();
		return;
	}
	send_to_char( "That had no effect.\n\r", ch);

	pop_call();
	return;
}

DO_SPELL(spell_ethereal)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA *paf, *paf_next;
	AFFECT_DATA af;

	push_call("spell_ethereal(%p,%p,%p,%p)",sn,level,ch,vo);

	if( IS_NPC( victim ) )
	{
		send_to_char( "You may only cast that on players.\n\r", ch );
		pop_call();
		return;
	}

	if ( IS_AFFECTED(victim, AFF2_ETHEREAL) )
	{
		for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
		{
			paf_next = paf->next;
			if( paf->bitvector==AFF2_ETHEREAL )
			{
				paf->duration  = number_fuzzy( level / 2 );
				send_to_char( "You faze out a bit more.\n\r", victim );
				if( victim != ch )
					send_to_char( "Ok.\n\r", ch );
				pop_call();
				return;
			}
		}
	}

	af.type      = sn;
	af.duration  = number_fuzzy( level / 2 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_ETHEREAL;
	affect_to_char( victim, &af );
	act( "$n partially fades out.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You partially fade out.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_astral)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af, *paf, *paf_next;

	push_call("spell_astral(%p,%p,%p,%p)",sn,level,ch,vo);

	if( IS_NPC( victim ) )
	{
		send_to_char( "You may only cast that on players.\n\r", ch );
		pop_call();
		return;
	}

	if ( IS_AFFECTED(victim, AFF2_ASTRAL) )
	{
		for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
		{
			paf_next = paf->next;
			if (paf->bitvector == AFF2_ASTRAL)
			{
				paf->duration  = number_fuzzy( level / 3 );
				send_to_char( "You no longer have the urge to return to your body.\n\r", victim );
				if (ch != victim)
				{
					act( "$N no longer has the urge to return to $S body.", ch, NULL, victim, TO_CHAR );
				}
				pop_call();
				return;
			}
		}
	}

	af.type      = sn;
	af.duration  = number_fuzzy( level / 3 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_ASTRAL;
	affect_to_char( victim, &af );
	act( "$n steps outside of $s body.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You step outside your body.\n\r", victim );
	pop_call();
	return;
}

DO_SPELL(spell_breath_water)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af, *paf, *paf_next;

	push_call("spell_breath_water(%p,%p,%p,%p)",sn,level,ch,vo);

	if( IS_NPC( victim ) )
	{
		send_to_char( "You may only cast that on players.\n\r", ch );
		pop_call();
		return;
	}

	if ( IS_AFFECTED(victim, AFF2_BREATH_WATER) )
	{
		for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
		{
			paf_next = paf->next;
			if( paf->bitvector == AFF2_BREATH_WATER )
			{
				paf->duration  = number_fuzzy( level / 3 );
				act( "$n takes another deep breath.", victim, NULL, NULL, TO_ROOM );
				send_to_char( "You take another deep breath.\n\r", victim );
				/*if( victim != ch )
				send_to_char( "Gills appear so water can be breathed.\n\r", victim );*/

				pop_call();
				return;
			}
		}
	}

	af.type      = sn;
	af.duration  = number_fuzzy( level / 3 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_BREATH_WATER;
	affect_to_char( victim, &af );
	act( "$n takes a deep breath.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You take a deep breath.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_sanctuary)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_sanctuary(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_SANCTUARY))
	{
		send_to_char( "That person already has Sanctuary.\n\r", ch);
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_SANCTUARY;
	affect_to_char( victim, &af );

	act( "$n is surrounded by a white aura.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are surrounded by a white aura.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_shield)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_shield(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "That person is already Shielded.\n\r", ch);
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = 8 + level/2;
	af.location  = APPLY_AC;
	af.modifier  = -20;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	act( "$n is surrounded by a force shield.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are surrounded by a force shield.\n\r", victim );
	pop_call();
	return;
}

DO_SPELL(spell_shocking_grasp)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_shocking_grasp(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level+60, level+90);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_paralyzing_embrace)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_paralyzing_embrace(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level+20, level+120);

	if ( saves_spell( level, ch, victim ) )
	{
		dam /= 2;
	}
	else if (number_bits(1) == 0)
	{
		AFFECT_DATA af;

		af.type      = sn;
		af.duration  = 1;
		if (!IS_NPC(victim))
		{
			if (number_bits(1) == 0)
			{
				af.location = APPLY_INT;
				af.modifier = -1;
			}
			else
			{
				af.location = APPLY_WIS;
				af.modifier = -1;
			}
		}
		else
		{
			af.location = APPLY_SAVING_SPELL;
			af.modifier = 1;
		}
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;
		affect_join( victim, &af );
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_sleep)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_sleep(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && !IS_NPC(victim))
	{
		if (!can_attack(ch, victim))
		{
			send_to_char("You cannot cast sleep on that person.\n\r", ch);
			pop_call();
			return;
		}
	}
	if ( IS_AFFECTED(victim, AFF_SLEEP) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	if (level < victim->level)
	{
		send_to_char( "They are too high of a level.\n\r", ch );
		pop_call();
		return;
	}
	if (saves_spell(level, ch, victim))
	{
		send_to_char( "Nothing happens.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level / 5;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_SLEEP;
	affect_to_char( victim, &af );

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

	pop_call();
	return;
}

DO_SPELL(spell_stone_skin)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_stone_skin(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level/2;
	af.location  = APPLY_AC;
	af.modifier  = -40;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	act( "$n's skin turns to stone.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your skin turns to stone.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_demon)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_demon(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}

	if (get_pets(ch) > 0)
	{
		send_to_char("You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	if (ch->position == POS_FIGHTING)
	{
		send_to_char( "You cannot cast this during combat.\n\r", ch);
		pop_call();
		return;
	}

	pMob = get_mob_index( 9901 );   /* Hard coded in emud.are */
	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= level * 3 / 4;
	mh->npcdata->damnodice	= mh->level;
	mh->npcdata->damsizedice	= 4;
	mh->npcdata->damplus	= 3;
	mh->max_hit			= 80 + mh->level * 4;
	mh->hit				= mh->max_hit;

	if (number_percent() < 66)
	{
		SET_BIT( mh->affected_by , AFF_CHARM );
		send_to_char( "A demon appears out of a rip in space.\n\r", ch);
		act("A demon appears out of a rip in space.", ch, NULL, NULL, TO_ROOM);
		add_follower( mh , ch );

		pop_call();
		return;
	}
	mh->level		= level;
	mh->max_hit	= 30 + mh->level * 10;
	send_to_char( "A demon appears out of a rip in space.\n\rHe seems angry.\n\r", ch);
	multi_hit(mh, ch, TYPE_UNDEFINED);

	pop_call();
	return;
}

DO_SPELL(spell_animate_dead)
{
	CHAR_DATA *mh;
	OBJ_DATA	*obj;

	push_call("spell_animate_dead(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char( "You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	if (ch->position == POS_FIGHTING)
	{
		send_to_char( "You cannot cast this during combat.\n\r", ch);
		pop_call();
		return;
	}

	for (obj = ch->in_room->first_content ; obj ; obj = obj->next_content)
	{
		if (obj->item_type == ITEM_CORPSE_NPC && obj->level <= level)
		{
			break;
		}
	}

	if (obj == NULL)
	{
		send_to_char( "You find no suitable corpse.\n\r", ch);
		pop_call();
		return;
	}

	mh		= create_mobile(mob_index[9903]);
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= obj->level;
	mh->hitroll			= 0;
	mh->npcdata->damnodice	= mh->level;
	mh->npcdata->damsizedice	= 3;
	mh->npcdata->damplus	= 2;
	mh->max_hit			= 50 + mh->level * 5;
	mh->hit				= mh->max_hit;

	SET_BIT( mh->affected_by , AFF_CHARM );
	SET_BIT( mh->act, ACT_UNDEAD );

	if (IS_SET(obj->extra_flags, ITEM_MOUNT))
	{
		SET_BIT( mh->act, ACT_MOUNT );
	}

	act("$n raises $p from death.", ch, obj, NULL, TO_ROOM );

	RESTRING(mh->name,			obj->name);
	RESTRING(mh->short_descr,	obj->short_descr);
	RESTRING(mh->long_descr,		"");
	RESTRING(mh->description,	"");

	while (obj->first_content)
	{
		if (number_bits(1))
		{
			obj_to_char(obj->first_content, mh);
		}
		else
		{
			junk_obj(obj->first_content);
		}
	}
	junk_obj(obj);

	do_wear(mh, "all");

	add_follower( mh , ch );

	pop_call();
	return;
}

DO_SPELL(spell_beast)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_beast(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char( "You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	if (ch->position == POS_FIGHTING)
	{
		send_to_char( "You cannot cast this during combat.\n\r", ch);
		pop_call();
		return;
	}

	pMob = get_mob_index( 9902 );   /* Hard coded in emud.are */
	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= level * 3 / 4;
	mh->npcdata->damnodice	= mh->level;
	mh->npcdata->damsizedice	= 2;
	mh->npcdata->damplus	= 5;
	mh->max_hit			= 30 + level * 4;
	mh->hit				= 30 + level * 4;

	SET_BIT(mh->affected_by, AFF_CHARM);

	send_to_char( "A shadow beast appears out of a ripple in the wall.\n\r", ch);
	add_follower( mh , ch );

	if (ch->fighting != NULL)
	{
		multi_hit( mh, ch->fighting->who, TYPE_UNDEFINED);
	}
	pop_call();
	return;
}

DO_SPELL(spell_shade)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_shade(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char("You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	pMob = get_mob_index( 9903 );   /* Hard coded in emud.are */
	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= level * 2 / 3;
	mh->npcdata->damnodice	= mh->level / 2;
	mh->npcdata->damsizedice	= 2;
	mh->npcdata->damplus	= 5;
	mh->max_hit			= 30 + level * 3;
	mh->hit				= 30 + level * 3;

	SET_BIT(mh->affected_by , AFF_CHARM);

	act("A Shade appears out of a ripple in the floor.", ch, NULL, NULL, TO_CHAR);
	act("A Shade appears out of a ripple in the floor.", ch, NULL, NULL, TO_ROOM);

	add_follower( mh , ch );

	pop_call();
	return;
}

DO_SPELL(spell_phantasm)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_phantasm(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char( "You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	pMob = get_mob_index( 9904 );   /* Hard coded in emud.are */
	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= level * 1 / 2;
	mh->npcdata->damnodice	= mh->level;
	mh->npcdata->damsizedice	= 5;
	mh->npcdata->damplus	= 50;
	mh->max_hit			= 50 + mh->level * 6;
	mh->hit				= 50 + mh->level * 6;

	SET_BIT( mh->affected_by , AFF_CHARM );

	send_to_char( "A phantasmal killer appears out of the palm of your hand.\n\r", ch);
	add_follower( mh , ch );

	if (ch->fighting != NULL)
	{
		multi_hit(mh, ch->fighting->who, TYPE_UNDEFINED );
	}
	pop_call();
	return;
}

DO_SPELL(spell_summon)
{
	CHAR_DATA *victim;

	push_call("spell_summon(%p,%p,%p,%p)",sn,level,ch,vo);

	if (target_name[0] == '\0')
	{
		send_to_char("Whom would you like to summon?\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_char_area(ch, target_name)) == NULL)
	{
		send_to_char( "There is nothing named like that.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_NPC(victim) && level / 3 < victim->level)
	{
		send_to_char( "You cannot summon those that do not wish to leave.\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(victim) && is_affected(victim, gsn_anti_magic_shell))
	{
		act("The flows of magic shatter against a shell surrounding $N.", ch, NULL, victim, TO_CHAR);
		act("Flows of magic shatter against your anti magic shell.", ch, NULL, victim, TO_VICT);
		pop_call();
		return;
	}

	if (victim == ch
	|| victim->in_room == NULL
	|| IS_SET(victim->in_room->room_flags, ROOM_SAFE)
	|| IS_SET(ch->in_room->room_flags, ROOM_SAFE)
	|| IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
	|| victim->in_room->sector_type == SECT_ETHEREAL
	|| victim->in_room->sector_type == SECT_ASTRAL
	|| ch->in_room->sector_type == SECT_ETHEREAL
	|| ch->in_room->sector_type == SECT_ASTRAL
	|| IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
	|| IS_SET(ch->in_room->area->flags, AFLAG_NOSUMMON)
	|| victim->level > level - 3
	|| victim->fighting != NULL
	|| find_keeper(victim) != NULL)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF_STABILITY) || saves_spell(level / 2, ch, victim))
	{
		send_to_char( "They resist your summoning spell.\n\r", ch);
		act("You feel a strange magical force pulling at you.", ch, NULL, victim, TO_VICT);

		pop_call();
		return;
	}

	act( "$n disappears suddenly.", victim, NULL, NULL, TO_ROOM );

	char_from_room( victim );
	char_to_room( victim, ch->in_room->vnum );

	act( "$n arrives suddenly.", victim, NULL, NULL, TO_ROOM );
	ch_printf(victim, "%s has summoned you!\n\r", get_name(ch));

	do_look( victim, "auto" );

	pop_call();
	return;
}

DO_SPELL(spell_banish)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	CHAR_DATA *rch;
	ROOM_INDEX_DATA *pRoomIndex;
	int cnt = 0;

	push_call("spell_banish(%p,%p,%p,%p)",sn,level,ch,vo);

	if (victim->in_room == NULL
	||  victim == ch
	||  IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
	||  IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
	||  IS_SET(ch->in_room->room_flags,  AFLAG_NOSUMMON)
	||  saves_spell(level, ch, victim))
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	if (saves_spell(level, ch, victim))
	{
		victim = ch;
	}

	for ( ; ; )
	{
		/*
			Better safe than freezing, added cnt - Scandum 01-04-2002
		*/
		if (cnt++ > 10000)
		{
			send_to_char("Nothing happens", ch);
			pop_call();
			return;
		}
		pRoomIndex = get_room_index(number_range(victim->in_room->area->low_r_vnum, victim->in_room->area->hi_r_vnum));

		if ( pRoomIndex != NULL )
		{
			if (IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE)
			||  IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY)
			||  IS_SET(pRoomIndex->room_flags, ROOM_SAFE)
			||  pRoomIndex == victim->in_room)
			{
				continue;
			}
			for (rch = pRoomIndex->first_person ; rch ; rch = rch->next_in_room)
			{
				if (IS_NPC(rch) && rch->pIndexData->pShop != NULL)
				{
					break;
				}
			}
			if (rch)
			{
				continue;
			}
			break;
		}
	}

	act( "$n is banished from existence.", victim, NULL, NULL, TO_ROOM );

	if (victim->position == POS_FIGHTING)
	{
		stop_fighting(victim, TRUE);
	}
	char_from_room( victim );
	char_to_room( victim, pRoomIndex->vnum );

	if (victim == ch)
	{
		send_to_char("You failed and banished yourself from existance.\n\r", victim);
	}
	else
	{
		send_to_char("You've been banished from existence.\n\r", victim);
	}
	do_look( victim, "auto" );

	pop_call();
	return;
}

DO_SPELL(spell_teleport)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	ROOM_INDEX_DATA *pRoomIndex;
	int attempts;

	push_call("spell_teleport(%p,%p,%p,%p)",sn,level,ch,vo);

	victim = ch;

	if (victim->in_room == NULL
	|| IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
	|| IS_SET(victim->in_room->area->flags, AFLAG_NORECALL)
	|| (!IS_NPC(ch) && victim->fighting != NULL)
	|| (IS_NPC(ch) && saves_spell(level, ch, victim)))
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	for (attempts = 0 ; attempts < 1000 ; attempts++)
	{

		pRoomIndex = get_room_index( number_range(1, MAX_VNUM-1));
		if(pRoomIndex != NULL)
		{
			if(!IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE)
			&& !IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY)
			&& !IS_SET(pRoomIndex->room_flags, ROOM_IS_CASTLE)
			&& !IS_SET(pRoomIndex->room_flags, ROOM_PET_SHOP)
			&& !IS_SET(pRoomIndex->room_flags, ROOM_RIP)
			&& !IS_SET(pRoomIndex->room_flags, ROOM_NO_RECALL)
			&& !IS_SET(pRoomIndex->area->flags, AFLAG_NOTELEPORT)
			&& !IS_SET(pRoomIndex->area->flags, AFLAG_NORECALL)
			&& pRoomIndex->area->average_level*2 < victim->level+15
			&& pRoomIndex->sector_type != SECT_ETHEREAL
			&& pRoomIndex->sector_type != SECT_ASTRAL
			&& !((!IS_IMMORTAL(victim))
			&& (victim->level<pRoomIndex->area->low_hard_range
			||  victim->level>pRoomIndex->area->hi_hard_range)))
			{
				break;
			}
		}
	}
	if (attempts >= 1000)
	{
		send_to_char("The earth decides you should remain where you are.\n\r", ch);
		pop_call();
		return;
	}

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

	if (victim->position == POS_FIGHTING && !IS_NPC(ch))
	{
		stop_fighting(victim, TRUE);
	}
	char_from_room(victim);
	char_to_room(victim, pRoomIndex->vnum);
	act("$n slowly fades into existence.", victim, NULL, NULL, TO_ROOM);
	do_look(victim, "auto");
	pop_call();
	return;
}

DO_SPELL(spell_ventriloquate)
{
	char buf1[MAX_STRING_LENGTH];
	char speaker[MAX_INPUT_LENGTH];
	CHAR_DATA *vch;

	push_call("spell_ventriloquate(%p,%p,%p,%p)",sn,level,ch,vo);

	if( ch->in_room == NULL )
	{
		pop_call();
		return;
	}
	for( vch = ch->in_room->first_person; vch != NULL; vch=vch->next_in_room )
	{
		if( !IS_NPC( vch ) && vch->level >= 99 )
		{
			sprintf( buf1, "You may not cast that with %s in the room.\n\r",
			capitalize( vch->name ) );
			send_to_char( buf1, ch );
			pop_call();
			return;
		}
	}

	target_name = one_argument( target_name, speaker );

	for ( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
	{
		if( vch->position >= POS_RESTING )
		{
			if ( !is_name_short( speaker, vch->name ) )
			{
				if( !saves_spell( level, ch, vch ) )
					sprintf( buf1, "%s%s says '%s'\n\r", get_color_string(vch,COLOR_SPEACH,VT102_DIM),
				capitalize( speaker ), target_name );
				else
					sprintf( buf1, "%sSomeone makes %s say '%s'\n\r", get_color_string(vch,COLOR_SPEACH,VT102_DIM),
				capitalize(speaker), target_name );
				send_to_char( buf1, vch );
			}
		}
	}

	pop_call();
	return;
}

DO_SPELL(spell_weaken)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_weaken(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ))
	{
		send_to_char( "They are already weakened.\n\r", ch );
		pop_call();
		return;
	}

	if( saves_spell( level, ch, victim ) )
	{
		send_to_char( "Nothing happens.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level / 10;
	if(IS_NPC(victim))
	{
		af.location  = APPLY_DAMROLL;
		af.modifier  = 0-(level/10)-2;
	}
	else
	{
		af.location  = APPLY_STR;
		af.modifier  = 0-(level/45)-2;
	}
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;

	affect_to_char( victim, &af );
	send_to_char( "Your strength flows out of your body.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "They now lost the strength to fight.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_word_of_recall)
{

	push_call("spell_word_of_recall(%p,%p,%p,%p)",sn,level,ch,vo);

	do_recall( (CHAR_DATA *) vo, NULL );

	pop_call();
	return;
}

/*
	Breath Spells
*/

DO_SPELL(spell_acid_breath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_acid_breath(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level*3+50, level*6+100);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}

	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_fire_breath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj_lose;
	OBJ_DATA *obj_next;
	int dam;

	push_call("spell_fire_breath(%p,%p,%p,%p)",sn,level,ch,vo);

	if (number_percent() < level / 2 && !saves_spell(level, ch, victim))
	{
		for (obj_lose = victim->first_carrying ; obj_lose ; obj_lose = obj_next)
		{
			obj_next = obj_lose->next_content;

			if (number_bits(2) != 0 || obj_lose->first_content)
			{
				continue;
			}

			switch (obj_lose->item_type)
			{
				default:			continue;
				case ITEM_POTION:	act("$p bubbles and boils!", victim, obj_lose, NULL, TO_CHAR);	break;
				case ITEM_SCROLL:	act("$p crackles and burns!", victim, obj_lose, NULL, TO_CHAR);	break;
				case ITEM_STAFF:	act("$p smokes and chars!", victim, obj_lose, NULL, TO_CHAR);	break;
				case ITEM_WAND:	act("$p sparks and sputters!", victim, obj_lose, NULL, TO_CHAR);	break;
				case ITEM_FOOD:	act("$p blackens and crisps!", victim, obj_lose, NULL, TO_CHAR);	break;
				case ITEM_PILL:	act("$p melts and drips!", victim, obj_lose, NULL, TO_CHAR);	break;
			}
			junk_obj( obj_lose );
		}
	}

	dam = number_range(level*10, level*12);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}

	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_frost_breath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj_lose;
	OBJ_DATA *obj_next;
	int dam;

	push_call("spell_frost_breath(%p,%p,%p,%p)",sn,level,ch,vo);

	if (number_percent() < level && !saves_spell(level, ch, victim))
	{
		for (obj_lose = victim->first_carrying ; obj_lose ; obj_lose = obj_next)
		{
			obj_next = obj_lose->next_content;

			if (number_bits(2) != 0 || obj_lose->first_content)
			{
				continue;
			}

			switch (obj_lose->item_type)
			{
				default:				continue;
				case ITEM_DRINK_CON:
				case ITEM_POTION:		act("$p freezes and shatters!", victim, obj_lose, NULL, TO_CHAR);	break;
			}
			junk_obj( obj_lose );
		}
	}

	dam = number_range(level*4, level*18);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_gas_breath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_gas_breath(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level*8, level*14);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	else
	{
		if (number_bits(3) == 0 && !IS_AFFECTED(victim, AFF_POISON))
		{
			AFFECT_DATA af;

			af.type      = gsn_poison;
			af.location  = APPLY_AC;
			af.modifier  = level;
			af.duration  = level/10;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF_POISON;

			affect_to_char( victim, &af );

			send_to_char( "You feel poison coursing through your vains.\n\r", victim );
			if (ch != victim)
			{
				send_to_char( "They now feel your poison.\n\r", ch );
			}
		}
	}
	damage(ch, victim, dam, sn);

	pop_call();
	return;
}

DO_SPELL(spell_lightning_breath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_lightning_breath(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level*6, level*16);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_psionic_shockwave)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_psionic_shockwave(%p,%p,%p,%p)",sn,level,ch,vo);

	dam = number_range(level*2, level*20);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_block_area)
{
	push_call("spell_block_area(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are restricted from blocking this area.\n\r",ch);
		pop_call();
		return;
	}

	if (ch->in_room->sector_type < 2 || ch->in_room->sector_type > 4)
	{
		send_to_char("The area pulsates with life but no plant life appears.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_BLOCK))
	{
		send_to_char("The area pulsates with life but nothing new appears.\n\r",ch);
		pop_call();
		return;
	}

	SET_BIT(ch->in_room->room_flags, ROOM_BLOCK);

	if (!del_room_timer(ch->in_room->vnum, ROOM_TIMER_UNBLOCK))
	{
		set_room_timer(ch->in_room->vnum, ROOM_TIMER_BLOCK, level / 2);
	}
	act( "All sorts of plant growth sprout up everywhere!", ch, NULL, NULL, TO_ROOM);
	act( "Your magic fills the area with plant life!", 	 ch, NULL, NULL, TO_CHAR);

	pop_call();
	return;
}

DO_SPELL(spell_write_spell)
{
	char buf[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	OBJ_DATA *scroll;
	int sn2,i;

	push_call("spell_write_spell(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_NPC(ch) || multi(ch, sn) == -1)
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if ((scroll = get_eq_char(ch, WEAR_HOLD)) == NULL || scroll->item_type != ITEM_SCROLL)
	{
		send_to_char("You need to hold the scroll you wish to write upon.\n\r",ch);
		pop_call();
		return;
	}

	for (i = 0 ; i < 100 ; i++)
	{
		sn2 = number_range(0, MAX_SKILL-1);

		if (skill_table[sn2].slot <= 0)
		{
			continue;
		}
		if (!IS_SET(skill_table[sn2].flags, FSKILL_SPELL))
		{
			continue;
		}
		if (ch->pcdata->learned[sn2] == 0)
		{
			continue;
		}
		break;
	}

	if (i >= 100)
	{
		send_to_char("Your mind goes blank!\n\r", ch);
		ch->mana = 0;
		pop_call();
		return;
	}

	if (level < 21)
	{
		sprintf(buf, "a haphazardly written scroll of %s", skill_table[sn2].name);
	}
	else if (level < 31)
	{
		sprintf(buf, "a decently scribed scroll of %s", skill_table[sn2].name);
	}
	else
	{
		sprintf(buf, "a skillfully crafted scroll of %s", skill_table[sn2].name);
	}

	sprintf(buf2, "scroll %s", skill_table[sn2].name);
	RESTRING(scroll->name, buf2);
	RESTRING(scroll->short_descr, buf);
	RESTRING(scroll->description, buf);

	scroll->cost		= 0;
	scroll->level		= level * 3 / 4;
	scroll->value[0]	= level;
	scroll->value[1]	= sn2;
	scroll->value[2]	= 0;
	scroll->value[3]	= 0;

	SET_BIT(scroll->extra_flags, ITEM_MODIFIED);

	act("$n writes what is hoped to be a useful spell.",	ch, scroll, NULL, TO_ROOM);
	act("You enter a trance and.. ..you now hold $p!",	ch, scroll, NULL, TO_CHAR);

	pop_call();
	return;
}

DO_SPELL(spell_homonculous)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_homonculous(%p,%p,%p,%p)",sn,level,ch,vo);

	if (ch->desc == NULL || ch->desc->original != NULL)
	{
		send_to_char( "You already are switched into something.\n\r", ch);
		pop_call();
		return;
	}

	pMob	= get_mob_index( 9900 );   /* Hard coded in emud.are */
	mh	= create_mobile( pMob );
	char_to_room(mh, ch->in_room->vnum);

	act("A clap of thunder and a small, ugly creature appears!",	ch, NULL, NULL, TO_ROOM);
	act("A clap of thunder and you suddenly feel smaller!",		ch, NULL, NULL, TO_CHAR);

	ch->desc->character 	= mh;
	ch->desc->original  	= ch;
	mh->desc            	= ch->desc;
	ch->desc            	= NULL;
	ch->pcdata->switched	= TRUE;

	pop_call();
	return;
}

DO_SPELL(spell_enhance_object)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA af;
	int stat;

	push_call("spell_enhance_object(%p,%p,%p,%p)",sn,level,ch,vo);

	if (obj->owned_by)
	{
		send_to_char( "You cannot enhance that object.\n\r", ch);
		pop_call();
		return;
	}

	stat = UMIN(1 + (level-1) / 25, 6);

	switch (obj->item_type)
	{
		case ITEM_ARMOR:
			af.location = APPLY_AC;
			af.modifier = 0-stat;
			break;
		case ITEM_WEAPON:
			af.location = APPLY_HITROLL;
			af.modifier = stat;
			break;
		default:
			send_to_char("You cannot enhance that kind of an object.\n\r", ch);
			pop_call();
			return;
	}

	obj->owned_by	= ch->pcdata->pvnum;

	SET_BIT(obj->extra_flags, ITEM_MODIFIED);

	af.type		= sn;
	af.duration	= -1;
	af.bittype	= AFFECT_TO_NONE;
	af.bitvector	= 0;

	affect_to_obj(obj, &af);

	char_reset( ch );

	act("$p has been enhanced.", ch, obj, NULL, TO_CHAR);

	pop_call();
	return;
}

DO_SPELL(spell_mage_shield)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_mage_shield(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level/3;
	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = -level/5;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	act( "$n is quickly covered by a shimmering glow.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are quickly covered by a shimmering glow.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_rift)
{
	char buf[MAX_INPUT_LENGTH];
	EXIT_DATA *pexit;
	ROOM_INDEX_DATA *to_room;
	int door, rip_door;

	push_call("spell_rift(%p,%p,%p,%p)",sn,level,ch,vo);

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

	if (!IS_SET(ch->in_room->room_flags, ROOM_RIP))
	{
		send_to_char("You can only create rifts from inside of a rip.\n\r",ch);
		pop_call();
		return;
	}

	to_room = get_rift_room(ch, value);

	/*
		pick a random exit
	*/

	for (rip_door = 0 ; rip_door < 12 ; rip_door++)
	{
		door = number_door();

		if (ch->in_room->exit[door] && IS_SET(ch->in_room->exit[door]->exit_info, EX_ISDOOR))
		{
			send_to_char("Sorry, only one rift per rip.\n\r", ch);
			pop_call();
			return;
		}

		if (to_room->exit[door] == NULL && ch->in_room->exit[rev_dir[door]] == NULL)
		{
			rip_door = rev_dir[door];
			break;
		}
	}

	if (rip_door == 12)
	{
		send_to_char("You failed to open a rift using that wrinkle in this room.\n\r",ch);
		pop_call();
		return;
	}

	/*
		Create 2-way connection
	*/

	create_exit(to_room, door);
	pexit = to_room->exit[door];
	RESTRING(pexit->description, "You see a rift in space and time.");

	pexit->exit_info		= EX_RIP;
	pexit->pvnum			= ch->pcdata->pvnum;
	pexit->to_room			= ch->in_room->vnum;


	create_exit(ch->in_room, rip_door);
	pexit = ch->in_room->exit[rip_door];

	sprintf(buf, "You see a wrinkle in time and space leading toward %s.", to_room->area->name);
	RESTRING(pexit->description, buf);
	pexit->to_room				= to_room->vnum;
	ch->in_room->exit[rip_door]	= pexit;

	act("Space and time appear to warp for a split second!", ch, NULL, NULL, TO_ROOM);

	switch (rip_door)
	{
		case DIR_UP:	sprintf(buf, "You cause space and time to warp irreparably above you."); 					break;
		case DIR_DOWN:	sprintf(buf, "You cause space and time to warp irreparably below you."); 					break;
		default:		sprintf(buf, "You cause space and time to warp irreparably to the %s.", dir_name[rip_door]);	break;
	}
	act (buf, ch, NULL, NULL, TO_CHAR );

	pop_call();
	return;
}

DO_SPELL(spell_rip)
{
	char buf[MAX_INPUT_LENGTH];
	EXIT_DATA *pexit;
	ROOM_INDEX_DATA *pRoomIndex;
	int door, rip_door, vnum, range;

	push_call("spell_rip(%p,%p,%p,%p)",sn,level,ch,vo);

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

	if (!IS_SET(ch->in_room->room_flags, ROOM_RIP))
	{
		if (IS_SET(ch->in_room->room_flags,	ROOM_SAFE)
		||  IS_SET(ch->in_room->room_flags,	ROOM_NO_RIP)
		||  IS_SET(ch->in_room->area->flags,	AFLAG_NORIP)
		||  IS_SET(ch->in_room->room_flags,	ROOM_NO_RECALL)
		||  IS_SET(ch->in_room->area->flags,	AFLAG_NORECALL))
		{
			send_to_char("You are prevented from ripping space here!\n\r",ch);
			pop_call();
			return;
		}
	}

	for (door = range = 0 ; door < 6 ; door++)
	{
		if (ch->in_room->exit[door] == NULL)
		{
			range++;
		}
	}
	if (range == 0)
	{
		send_to_char("You failed to find space to create a rip here.\n\r", ch);
		pop_call();
		return;
	}
	vnum		= number_range(1, range);
	rip_door	= 0;

	for (door = 0 ; door < 6 ; door++)
	{
		if (ch->in_room->exit[door] == NULL)
		{
			if (--vnum == 0)
			{
				rip_door = door;
				break;
			}
		}
	}

	/* find valid vnum */

	for (vnum = ROOM_VNUM_RIFT ; vnum < MAX_VNUM && get_room_index(vnum) != NULL ; vnum++);

	if (vnum >= MAX_VNUM)
	{
		send_to_char("You are prevented from ripping up the Realm!\n\r",ch);
		pop_call();
		return;
	}

	create_room(vnum);
	pRoomIndex = room_index[vnum];

	sprintf(buf, "Haven a la %s.", ch->name);
	pRoomIndex->name			= STRALLOC(buf);
	pRoomIndex->area			= room_index[ROOM_VNUM_LIMBO]->area;
	pRoomIndex->vnum			= vnum;
	pRoomIndex->description		= STRALLOC("You see an area that defies all description.");
	pRoomIndex->room_flags		= ROOM_RIP|ROOM_NO_MOB|ROOM_INDOORS|ROOM_NO_RECALL|ROOM_NO_SAVE|ROOM_SAFE;
	pRoomIndex->sector_type		= SECT_INSIDE;

	for (door = 0 ; door < MAX_LAST_LEFT ; door++)
	{
		pRoomIndex->last_left[door] = STRDUPE(str_empty);
	}

	/* new room exit points to old room */

	create_exit(pRoomIndex, rev_dir[rip_door]);
	pexit	= pRoomIndex->exit[rev_dir[rip_door]];

	RESTRING(pexit->description, "You see an opening exiting the fabric of space and time.");
	pexit->to_room	= ch->in_room->vnum;

	create_exit(ch->in_room, rip_door);
	pexit	= ch->in_room->exit[rip_door];

	RESTRING(pexit->description,	"You see an opening in the fabric of space and time.");
	pexit->exit_info	= EX_RIP;
	pexit->pvnum		= ch->pcdata->pvnum;
	pexit->to_room		= pRoomIndex->vnum;

	act("$n creates a room of haven $twards.", ch, dir_name[rip_door], NULL, TO_ROOM);
	ch_printf(ch, "You create a room of haven %swards.\n\r", dir_name[rip_door]);

	pop_call();
	return;
}

DO_SPELL(spell_envision)
{
	ROOM_INDEX_DATA *rift_room, *temp_room;

	push_call("spell_envision(%p,%p,%p,%p)",sn,level,ch,vo);

	rift_room	= get_rift_room(ch, value);
	temp_room	= ch->in_room;

	char_from_room(ch);
	char_to_room(ch, rift_room->vnum);

	ch_printf(ch, "Time space coordinates echo through your mind.\n\r");

	do_look(ch, "");

	char_from_room(ch);
	char_to_room(ch, temp_room->vnum);

	pop_call();
	return;
}

DO_SPELL(spell_illusion)
{
	CHAR_DATA *mh, *victim;
	char illusionname[MAX_INPUT_LENGTH];
	int i;

	push_call("spell_illusion(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char("You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	for (i = 0 ; target_name[i] != '\0' ; i++)
	{
		if (ispunct(target_name[i]) || isdigit(target_name[i]))
		{
			send_to_char("You failed to create such an abstract illusion.\n\r", ch);
			pop_call();
			return;
		}
	}
	mh	= create_mobile( get_mob_index( MOB_VNUM_ILLUSION ) );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= 3*level/4;
	mh->npcdata->damnodice	= mh->level;
	mh->npcdata->damsizedice	= 2;
	mh->npcdata->damplus	= 3;
	mh->max_hit			= 1;
	mh->hit				= mh->max_hit;

	if (target_name[0] == '\0')
	{
		STRFREE (mh->name);
		STRFREE (mh->short_descr);
		STRFREE (mh->long_descr);
		STRFREE (mh->description);

		sprintf(illusionname, "%s^", ch->name);
		mh->name			= STRALLOC(illusionname);

		if (IS_NPC(ch))
		{
			mh->short_descr = STRALLOC(ch->short_descr);
		}
		else
		{
			mh->short_descr = STRALLOC(ch->name);
		}

		mh->long_descr		= STRALLOC(ch->long_descr);
		mh->description	= STRALLOC(ch->description);
		mh->race			= ch->race;
		mh->sex			= ch->sex;
	}
	else if ((victim = get_char_room(ch, target_name)) != NULL && victim != mh)
	{
		for (illusionname[0] = '\0', i = 0 ; victim->name[i] != '\0' ; i++)
		{
			if (victim->name[i] == ' ')
			{
				strcat(illusionname, "^ ");
			}
			else
			{
				cat_sprintf(illusionname, "%c", victim->name[i]);
			}
		}
		strcat(illusionname, "^");

		STRFREE(mh->name);
		STRFREE(mh->short_descr);
		STRFREE(mh->long_descr);
		STRFREE(mh->description);

		if (IS_NPC(victim))
		{
			mh->short_descr = STRALLOC(victim->short_descr);
		}
		else
		{
			mh->short_descr = STRALLOC(victim->name);
		}
		mh->name			= STRALLOC(illusionname);
		if (IS_NPC(victim))
		{
			if (victim->long_descr[0] != '\0')
			{
				sprintf(illusionname, "%s", ansi_strip(ansi_translate(victim->long_descr)));
			}
			else
			{
				illusionname[0] = '\0';
			}
		}
		else
		{
			strcpy(illusionname, victim->long_descr);
		}

		mh->long_descr		= STRALLOC(illusionname);
		mh->description	= STRALLOC(victim->description);
		mh->race			= victim->race;
		mh->sex			= victim->sex;
	}
	else
	{
		for (illusionname[0] = '\0', i = 0 ; target_name[i] != '\0' ; i++)
		{
			if (target_name[i] == ' ')
			{
				strcat(illusionname, "^ ");
			}
			else
			{
				cat_sprintf(illusionname, "%c", target_name[i]);
			}
		}
		strcat(illusionname, "^");

		STRFREE (mh->name);
		STRFREE (mh->short_descr);
		STRFREE (mh->long_descr);
		STRFREE (mh->description);

		mh->name			= STRALLOC(illusionname);
		mh->short_descr	= STRALLOC(target_name);
		mh->long_descr		= STRALLOC("");
		mh->description	= STRALLOC("");

		mh->race			= ch->race;
		mh->sex			= ch->sex;
	}

	SET_BIT( mh->affected_by , AFF_CHARM );
	act("$N takes shape before your eyes.",ch,NULL,mh,TO_CHAR);
	act("$N takes shape before your eyes.",ch,NULL,mh,TO_ROOM);
	add_follower( mh , ch );
	pop_call();
	return;
}

DO_SPELL(spell_winged_call)
{
	CHAR_DATA *mob;

	push_call("spell_winged_call(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char("You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	mob = create_mobile(mob_index[MOB_VNUM_WINGED_CALL]);

	char_to_room(mob, ch->in_room->vnum);

	mob->level				= level / 2;
	mob->npcdata->damnodice		= level / 2;
	mob->npcdata->damsizedice	= 2;
	mob->npcdata->damplus		= level / 2;
	mob->max_hit				= level * 5;
	mob->hit					= mob->max_hit;

	SET_BIT(mob->affected_by , AFF_CHARM);

	act("You summon $N from the high mountains.", ch, NULL, mob, TO_CHAR);
	act("$n summons $N from the high mountains.", ch, NULL, mob, TO_ROOM);

	add_follower(mob, ch);

	pop_call();
	return;
}

DO_SPELL(spell_mirror_image)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_mirror_image(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "Mirror images can't be compounded!\n\r", ch );
		pop_call();
		return;
	}
	af.type = sn;

	if (!IS_NPC(ch) && ch->pcdata->mclass[CLASS_SORCERER] > 0)
	{
		af.duration = (ch == victim) ? 10 : 5;
		af.modifier = (ch == victim) ? number_fuzzy(level / 8) : number_fuzzy(level / 20);
	}
	else
	{
		af.duration  = 10;
		af.modifier  = 1 + level / 30;
	}
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_MIRROR_IMAGE;
	affect_to_char( victim, &af );
	send_to_char("Several of you take a step out and away from yourself.\n\r", victim );
	if ( ch != victim )
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_hallucinate)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_hallucinate(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They can't get any worse!\n\r", ch );
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF_TRUESIGHT))
	{
		act( "$N sees through the veil on reality you try to impose.", ch, NULL, victim, TO_CHAR );
		act( "You see through the veil on reality $n attempts to impose.", ch, NULL, victim, TO_VICT );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level/10; /* Used to be level/31 , longer trip for those halu dudes now :)  -  Scandum */
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_HALLUCINATE;
	affect_to_char( victim, &af );
	send_to_char("Wow!  You see lot's of pretty colors!\n\r", victim );
	if(ch!=victim)
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_stability)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_stability(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_STABILITY))
	{
		send_to_char("They already feel the solidity of the earth.\n\r", ch);
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/4;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_STABILITY;
	affect_to_char( victim, &af );

	send_to_char("The weight of the earth begins to creep into your soul.\n\r", victim );

	if (ch != victim)
	{
		send_to_char( "You fill their soul with the weight of the earth.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_confusion)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_confusion(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF2_CONFUSION) || saves_spell(level, ch, victim))
	{
		send_to_char( "You cast confusion!\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/30+1;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_CONFUSION;

	affect_to_char( victim, &af );
	send_to_char( "Your eyes shimmer.\n\r", victim );
	if (ch != victim)
	{
		send_to_char( "You cast confusion!\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_sanctify)
{
	ROOM_INDEX_DATA *room;
	CHAR_DATA *fch;
	char buf[MAX_INPUT_LENGTH];

	push_call("spell_sanctify(%p,%p,%p,%p)",sn,level,ch,vo);

	if (ch->in_room == NULL)
	{
		pop_call();
		return;
	}

	room = ch->in_room;

	if (IS_SET(room->room_flags, ROOM_SAFE))
	{
		send_to_char( "This room is already safe enough.\n\r", ch );
		pop_call();
		return;
	}

	for (fch = room->first_person ; fch ; fch = fch->next_in_room)
	{
		if (fch->position == POS_FIGHTING || fch->fighting != NULL)
		{
			send_to_char( "There is too much violence in the room to cast sanctify.\n\r", ch );
			pop_call();
			return;
		}
	}

	/* Can't sanctify the arena.  Presto  8-1-98 */

	if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
	{
		send_to_char("The arena may not be sanctified.\n\r", ch);
		pop_call();
		return;
	}

	set_room_timer(room->vnum, ROOM_TIMER_SANCTIFY, 1 + level / 5);
	room->sanctify_char = ch;

	SET_BIT(room->room_flags, ROOM_SAFE);

	send_to_char( "The room becomes sanctified, and is a sanctuary for all.\n\r", ch);
	sprintf(buf, "$n prays to %s and makes this small area a sanctuary to all.", get_god_name(which_god(ch)));
	act(buf, ch, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_globe_of_darkness)
{
	push_call("spell_globe_of_darkness(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_GLOBE))
	{
		send_to_char("This room is already shrouded in darkness.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char( "The darkness dissipates immediately.\n\r", ch );
		pop_call();
		return;
	}

	SET_BIT(ch->in_room->room_flags, ROOM_GLOBE);

	set_room_timer(ch->in_room->vnum, ROOM_TIMER_GLOBE, 1 + level/20);

	act("The light around you dissolves into darkness.", ch, NULL, NULL, TO_CHAR);
	act("The light around you dissolves into darkness.", ch, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_ice_layer)
{
	push_call("spell_ice_layer(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_ICE))
	{
		send_to_char("This room is already covered by ice.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char( "The ice melts immediately.\n\r", ch );
		pop_call();
		return;
	}

	switch (ch->in_room->sector_type)
	{
		case SECT_ETHEREAL:
		case SECT_ASTRAL:
			send_to_char("The ice slowly drifts away into the unknown.\n\r", ch);
			pop_call();
			return;

		case SECT_UNDER_WATER:
			send_to_char("The ice slowly floats up toward the surface.\n\r", ch);
			pop_call();
			return;
	}

	/*
		Possible to add duration based on temperature, farenheit to celcius
		is: -32 times 5 div by 9
	*/

	SET_BIT(ch->in_room->room_flags, ROOM_ICE);

	set_room_timer(ch->in_room->vnum, ROOM_TIMER_ICE, 1 + level/30);

	act("Water emerges at your command, freezing into sheets of ice.", ch, NULL, NULL, TO_CHAR);
	act("Water emerges at $n's command, freezing into sheets of ice.", ch, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_benediction)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_benediction(%p,%p,%p,%p)",sn,level,ch,vo);

	if (victim->position == POS_FIGHTING)
	{
		send_to_char( "They are fighting.\n\r", ch );
		pop_call();
		return;
	}

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	if (ch->level < victim->level*3/4
	||  ch->level > victim->level*4/3)
	{
		ch_printf(ch,  "Your god feels that %s is unworthy of your benediction.\n\r", get_name(victim) );
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_HIT;
	af.modifier  = level * 4;

	if (victim != ch)
	{
		af.modifier /= 2;
	}

	af.duration  = level / 8;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;

	affect_to_char( victim, &af );

	if (victim != ch)
	{
		act("You make a sign of benediction over $N's head.", ch, NULL, victim, TO_CHAR);
		act("$n makes a sign of benediction over your head.", ch, NULL, victim, TO_VICT);
	}
	else
	{
		act("You make the sign of benediction over your head.", ch, NULL, NULL, TO_CHAR);
		act("$n makes the sign of benediction over $s head.",   ch, NULL, NULL, TO_ROOM);
	}
	pop_call();
	return;
}

DO_SPELL(spell_righteous_fury)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_righteous_fury(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( victim->position == POS_FIGHTING )
	{
		send_to_char( "They are fighting.\n\r", ch );
		pop_call();
		return;
	}
	if( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = number_fuzzy (level /10);
	af.location  = APPLY_HITROLL;
	af.modifier  = number_fuzzy (level / 7);
	if (victim != ch)
	{
		af.modifier /= 2;
	}
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	af.location  = APPLY_DAMROLL;
	af.modifier  = number_fuzzy (level / 8);
	if (victim != ch)
	{
		af.modifier /= 2;
	}
	affect_to_char( victim, &af );

	if (ch != victim)
	{
		act("You invoke the wrath of your god, filling $N with righteous fury.", ch, NULL, victim, TO_CHAR);
		act("$n invokes the wrath of $s god, filling you with righteous fury.",  ch, NULL, victim, TO_VICT);
		act("$n invokes the wrath of $s god, filling $N with righteous fury.",   ch, NULL, victim, TO_NOTVICT);
	}
	else
	{
		act("You invoke the wrath of your god, filling yourself with divine fury.", ch, NULL, victim, TO_CHAR);
		act("$n invokes the wrath of $s god, filling $mself with divine fury.",     ch, NULL, victim, TO_NOTVICT);
	}

	pop_call();
	return;
}

DO_SPELL(spell_soothing_touch)
{
	CHAR_DATA *gch;
	int heal;

	push_call("spell_soothing_touch(%p,%p,%p,%p)",sn,level,ch,vo);

	heal = dice(10, 10) + level*5/2 ;

	for (gch = ch->in_room->first_person ; gch ; gch = gch->next_in_room)
	{
		if (!is_same_group(gch, ch))
		{
			continue;
		}
		if (is_safe_magic(ch, gch, sn))
		{
			continue;
		}
		gch->hit = UMIN( gch->hit + heal, gch->max_hit );
		update_pos( gch );

		if (gch != ch)
		{
			act("$n's soothing touch makes your wounds close and your pain fade.", ch, NULL, gch, TO_VICT );
		}
		else
		{
			act("Your soothing touch makes wounds close and pain fade.", ch, NULL, NULL, TO_CHAR );
		}
	}
	pop_call();
	return;
}

DO_SPELL(spell_farheal)
{
	CHAR_DATA *victim;
	int heal;

	push_call("spell_farheal(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( ( victim = get_player_world( ch, target_name ) ) == NULL)
	{
		send_to_char( "Farheal who ?\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && ch->pcdata->mclass[ch->class] != ch->level)
	{
		send_to_char("You lack the single minded devotion to reach through the void.\n\r", ch);
		pop_call();
		return;
     }

	if (victim->in_room == NULL
		||   IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
		||   IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
		||   victim->in_room->sector_type == SECT_ETHEREAL
		||   victim->in_room->sector_type == SECT_ASTRAL
		||   ch->in_room->sector_type == SECT_ETHEREAL
		||   ch->in_room->sector_type == SECT_ASTRAL
		||   IS_NPC(victim)
		||   victim->fighting != NULL )
	{
		ch_printf(ch, "You can not reach %s through the void.\n\r",
		get_name(victim));
		pop_call();
		return;
	}
	if (victim == ch)
	{
		send_to_char( "You can't farheal yourself!\n\r", ch);
		pop_call();
		return;
	}
	if (victim->in_room == ch->in_room)
	{
		ch_printf(ch, "%s is in the same room as you!\n\r",
		get_name(victim));
		pop_call();
		return;
	}
	heal = dice(11, 9) + level;
	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );

	act( "$n reaches through the void to fill you with healing energy.", ch, NULL, victim, TO_VICT );
	act ( "You reach through the void to $N, filling $M with healing energy.", ch, NULL, victim, TO_CHAR );

	pop_call();
	return;
}

DO_SPELL(spell_holy_word)
{
	push_call("spell_holy word(%p,%p,%p,%p)",sn,level,ch,vo);

	pop_call();
	return;
}

DO_SPELL(spell_unholy_word)
{
	push_call("spell_unholy_word(%p,%p,%p,%p)",sn,level,ch,vo);

	pop_call();
	return;
}

DO_SPELL(spell_invigorate)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal, scale_top, scale_bot;
	char buf[MAX_INPUT_LENGTH];

	push_call("spell_invigorate(%p,%p,%p,%p)",sn,level,ch,vo);

	if( victim==NULL || victim->in_room == NULL || ch->in_room==NULL
		|| victim->in_room != ch->in_room )
	{
		send_to_char( "That person is not here.\n\r", ch );
		pop_call();
		return;
      }

	scale_top = 29;  /* The fraction for the hp/mana ratio */
	scale_bot = 7;

	if( value == -1 || value > ch->mana )
		value = ch->mana;

	heal = value * scale_top / scale_bot ;
	if( victim->move + heal > victim->max_move )
		heal = victim->max_move - victim->move ;
	value = ( heal * scale_bot / scale_top );

	sprintf( buf, "Invigorating %d moves for %d mana.\n\r", heal, value + get_mana(ch,sn));
	send_to_char( buf, ch);

	victim->move += heal;
	ch->mana -= value;

	send_to_char( "A delicious chill runs up your spine, cleansing the lethargy from your limbs.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_improved_invis)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_improved_invis(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF_IMP_INVISIBLE))
	{
		send_to_char("They are already invisible.\n\r", ch);
		pop_call();
		return;
	}

	act( "Something unseen enshrouds $n.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = number_fuzzy(level / 4);
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_IMP_INVISIBLE;
	affect_to_char( victim, &af );

	act("You are enshrouded by something unseen.", victim, NULL, NULL, TO_CHAR);
	act("$n is enshrouded by something unseen.",   victim, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}

DO_SPELL(spell_truesight)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_truesight(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(ch, AFF_TRUESIGHT))
	{
		send_to_char( "Your eyes already see through the facades of mundane reality.\n\r", ch);
		pop_call();
		return;
	}
	if (IS_AFFECTED(ch, AFF_BLIND))
	{
		affect_strip(victim, gsn_blindness);
	}
	af.type      = sn;
	af.duration  = number_fuzzy(level/4);
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_TRUESIGHT;
	affect_to_char( victim, &af );

	send_to_char( "Your eyes gain the ability to see through the facades of mundane reality.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_anti_magic_shell)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_anti_magic_shell(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "You are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = URANGE(2, number_fuzzy(4), 6);
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	send_to_char( "The flows of magic recede from your body.\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_smoke)
{
	ROOM_INDEX_DATA *room;

	push_call("spell_smoke(%p,%p,%p,%p)",sn,level,ch,vo);

	if( ch->in_room == NULL )
	{
		pop_call();
		return;
	}

	room = ch->in_room;

	if( IS_SET(room->room_flags, ROOM_SAFE ) )
	{
		send_to_char( "The smoke dissipates immediately.\n\r", ch );
		pop_call();
		return;
	}

	SET_BIT( room->room_flags, ROOM_SMOKE );

	set_room_timer(room->vnum, ROOM_TIMER_SMOKE, 1 + level / 10);

	act( "You conjure up an impenetrable cloud of dark purple smoke.", ch, NULL, NULL, TO_CHAR );
	act( "$n conjures up an impenetrable cloud of dark purple smoke.", ch, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_nightmare)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_nightmare(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		act( "$N is still recovering from $S last fright!", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}

	if (IS_EVIL(victim) && saves_spell(level/3, ch, victim))
	{
		act("$N smirks at your feeble attempt to scare $M.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
	else if( saves_spell( level, ch, victim ) )
	{
		send_to_char( "Nothing happens.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_NPC(victim) )
	{
		af.type      = sn;
		af.duration  = number_fuzzy(level / 5);
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;

		af.location  = APPLY_DAMROLL;
		af.modifier  = 0-(level/7);
		affect_to_char( victim, &af );

		af.location  = APPLY_HITROLL;
		af.modifier  = 0-(level/7);
		affect_to_char( victim, &af );

		af.location  = APPLY_SAVING_SPELL;
		af.modifier  = number_fuzzy(level/7);
		affect_to_char( victim, &af );
	}
	else
	{
		af.type      = sn;
		af.duration  = number_fuzzy(level/21);
		af.bitvector = 0;
		af.bittype   = AFFECT_TO_NONE;
		af.location  = APPLY_STR;
		af.modifier  = 0 - number_fuzzy(level/21);
		affect_to_char( victim, &af );

		af.location  = APPLY_DEX;
		af.modifier  = 0 - number_fuzzy(level/14);
		affect_to_char( victim, &af );

		af.location  = APPLY_SAVING_SPELL;
		af.modifier  = number_fuzzy(level/7);
		affect_to_char( victim, &af );
	}
	if (ch != victim)
	{
		ch_printf(victim, "A nightmarish apparition flies from %s's hands towards your face!\n\r", get_name(ch) );
		ch_printf(ch, "A nightmarish apparition flies from your hands towards %s's face!\n\r", get_name(victim) );
	}
	else
	{
		send_to_char("Ok.\n\r", ch);
	}

	damage( ch, victim, number_range(level/2, level*2), sn);

	pop_call();
	return;
}

DO_SPELL(spell_possess)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_posses(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_NPC(ch) || ch->desc->original)
	{
		send_to_char("You are not in your original state.\n\r", ch);
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char("You already have control over yourself.\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(victim) || !can_mass_cast(ch, victim))
	{
		send_to_char("They seem to be unaffected by your magic.\n\r", ch);
		pop_call();
		return;
	}

	if (victim->desc)
	{
		ch_printf(ch, "%s is already possessed.\n\r", victim->short_descr);
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF2_POSSESS)
	||  level / 2 < victim->level
	||  saves_spell(level/2, ch, victim))
	{
		act("$N is unhappy with that you tried to seize control of $S brain.", ch, NULL, victim, TO_CHAR);
		multi_hit(victim, ch, TYPE_UNDEFINED);
		pop_call();
		return;
	}

	SET_BIT(victim->act,ACT_SENTINEL);
	REMOVE_BIT(victim->act, ACT_AGGRESSIVE);

	af.type      = sn;
	af.duration  = 12;
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_POSSESS;
	affect_to_char( victim, &af );

	log_printf("%s has possessed %s",get_name(ch), victim->short_descr);

	ch->desc->character = victim;
	ch->desc->original  = ch;
	victim->desc        = ch->desc;
	ch->desc            = NULL;
	ch->pcdata->switched = TRUE;

	ch_printf(victim, "You have possessed %s.\n\r", get_name(victim));

	pop_call();
	return;
}

DO_SPELL(spell_transport)
{
	CHAR_DATA *victim;
	char arg3[MAX_STRING_LENGTH];
	OBJ_DATA *obj;

	push_call("spell_transport(%p,%p,%p,%p)",sn,level,ch,vo);

	target_name = one_argument(target_name, arg3 );

	if ((victim = get_player_world(ch, target_name)) == NULL
	||   victim == ch
	||   IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
	||   IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
	||   victim->in_room->sector_type == SECT_ASTRAL
	||   victim->in_room->sector_type == SECT_ETHEREAL
	||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
	||   IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
	||   victim->level >= level + 15
	||  (IS_NPC(victim) && saves_spell( level, ch, victim )) )
	{
		send_to_char("Your transport spell failed!\n\r", ch);
		pop_call();
		return;
	}

	if (victim->in_room == ch->in_room)
	{
		send_to_char("They are right beside you!", ch);
		pop_call();
		return;
	}

	if ((obj = get_obj_carry(ch, arg3)) == NULL
	||  (victim->carry_weight + get_obj_weight (obj)) > can_carry_w(victim))
	{
		send_to_char( "Your transport spell failed!\n\r", ch);
		pop_call();
		return;
	}

	if (IS_OBJ_STAT(obj, ITEM_NODROP))
	{
		send_to_char( "You can't seem to let go of it.\n\r", ch );
		pop_call();
		return;
	}

	act( "$p slowly dematerializes...", ch, obj, NULL, TO_CHAR );
	act( "$p slowly dematerializes from $n's hands..", ch, obj, NULL, TO_ROOM );

	obj_from_char( obj );
	obj_to_char( obj, victim );

	act( "$p from $n appears in your hands!", ch, obj, victim, TO_VICT);
	act( "$p appears in $n's hands!", victim, obj, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_slow)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_slow(%p,%p,%p,%p)",sn,level,ch,vo);

	if(IS_SET(ch->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You are forbidden from casting that here.\n\r", ch);
		pop_call();
		return;
	}

	if( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	if ( IS_AFFECTED(victim, AFF_HASTE) )
	{
		REMOVE_BIT(victim->act, AFF_HASTE);
	}

	act( "$n slows down.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = number_fuzzy(level/9);
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	victim->speed = UMIN(victim->speed, get_max_speed(victim));

	send_to_char( "You slow down.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );

	pop_call();
	return;
}

DO_SPELL(spell_brew_potion)
{
	char buf[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	OBJ_DATA *potion;
	int sn2,i;

	push_call("spell_brew_potion(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_NPC(ch) || multi(ch, sn) == -1)
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if ((potion = get_eq_char(ch, WEAR_HOLD)) == NULL || potion->item_type != ITEM_POTION)
	{
		send_to_char("You need to hold a vial for the potion you shall brew.\n\r", ch);
		pop_call();
		return;
	}

	for (i = 0 ; i < 100 ; i++)
	{
		sn2 = number_range(0, MAX_SKILL -1);

		if (skill_table[sn2].slot <= 0)
		{
			continue;
		}
		if (!IS_SET(skill_table[sn2].flags, FSKILL_SPELL))
		{
			continue;
		}
		if (ch->pcdata->learned[sn2] == 0)
		{
			continue;
		}
		break;
	}

	if (i >= 100)
	{
		send_to_char("Your mind goes blank!\n\r",ch);
		ch->mana = 0;
		pop_call();
		return;
	}

	if (level < 51)
	{
		sprintf(buf, "a murky potion of %s", skill_table[sn2].name);
		sprintf(buf2, "murky potion %s", skill_table[sn2].name);
	}
	else if (level < 61)
	{
		sprintf(buf, "a cloudy potion of %s", skill_table[sn2].name);
		sprintf(buf2, "cloudy potion %s", skill_table[sn2].name);
	}
	else
	{
		sprintf(buf, "a clear potion of %s", skill_table[sn2].name);
		sprintf(buf2, "clear potion %s", skill_table[sn2].name);
	}

	RESTRING(potion->name, buf2);
	RESTRING(potion->short_descr, buf);
	RESTRING(potion->long_descr, "");
	RESTRING(potion->description, buf);

	potion->cost		= 0;
	potion->level		= level * 3 / 4;
	potion->value[0]	= level;
	potion->value[1]	= sn2;
	potion->value[2]	= 0;
	potion->value[3]	= 0;

	SET_BIT(potion->extra_flags, ITEM_MODIFIED);

	act("$n brews up a potion.",						ch, potion, NULL, TO_ROOM);
	act("You enter a trance and...  ...you now hold $p!",	ch, potion, NULL, TO_CHAR);

	pop_call();
	return;
}

DO_SPELL(spell_elemental)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;

	push_call("spell_elemental(%p,%p,%p,%p)",sn,level,ch,vo);

	if (get_pets(ch) > 0)
	{
		send_to_char( "You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	switch (ch->in_room->sector_type)
	{
		case SECT_LAVA:
			send_to_char( "A fiery shape emerges from the flames to do your bidding.\n\r", ch );
			pMob = get_mob_index(MOB_VNUM_FIRE_ELEMENTAL);
			break;
		case SECT_LAKE:
		case SECT_RIVER:
		case SECT_OCEAN:
		case SECT_UNDER_WATER:
			send_to_char( "A ripple in the water forms into a man sized shape.\n\r", ch );
			pMob = get_mob_index(MOB_VNUM_WATER_ELEMENTAL);
			break;
		case SECT_AIR :
			send_to_char( "A blast of wind circles you, ready to do your bidding.\n\r", ch );
			pMob = get_mob_index(MOB_VNUM_AIR_ELEMENTAL);
			break;
		case SECT_FOREST : case SECT_DESERT       : case SECT_MOUNTAIN   :
		case SECT_HILLS  : case SECT_UNDER_GROUND : case SECT_DEEP_EARTH :
			send_to_char( "A large mound of earth rises up out of the ground to do your bidding.\n\r", ch );
			pMob = get_mob_index(MOB_VNUM_EARTH_ELEMENTAL);
			break;
		default :
			send_to_char( "No elementals appear to do your bidding.\n\r", ch );
			pop_call();
			return;
	}

	if (pMob == NULL)
	{
		send_to_char( "You cannot create an elemental now.\n\r", ch );
		pop_call();
		return;
    }

	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum );

	mh->level				= level * 1 / 2;
	mh->npcdata->damnodice	= mh->level / 2;
	mh->npcdata->damsizedice	= 2;
	mh->npcdata->damplus	= 7;
	mh->max_hit			= 30 + level * 5;
	mh->hit				= 30 + level * 5;

	SET_BIT( mh->affected_by , AFF_CHARM );

	add_follower( mh , ch );

	if (ch->fighting != NULL)
	{
		multi_hit(mh, ch->fighting->who, TYPE_UNDEFINED);
	}
	pop_call();
	return;
}

DO_SPELL(spell_unbarring_ways)
{
	int door;
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit;
	EXIT_DATA *pexit_rev;

	push_call("spell_unbarring_ways(%p,%p,%p,%p)",sn,level,ch,vo);

	if (target_name[0] == '\0')
	{
		send_to_char( "What direction do you wish to cast this spell in?\n\r", ch);
		pop_call();
		return;
	}

	if ((door = find_door(ch, target_name)) >= 0)
	{
 		pexit = ch->in_room->exit[door];

		if (pexit == NULL)
		{
			send_to_char( "There is no door in that direction.\n\r", ch);
			pop_call();
			return;
		}
		if (IS_SET(pexit->exit_info, EX_MAGICPROOF))
		{
			send_to_char( "It remains firm.\n\r",  ch );
			pop_call();
			return;
		}

		REMOVE_BIT(pexit->exit_info, EX_LOCKED);
		REMOVE_BIT(pexit->exit_info, EX_CLOSED);
		SET_BIT   (pexit->exit_info, EX_UNBARRED);

		if ((to_room = room_index[pexit->to_room]) != NULL
		&&  (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
		&&   room_index[pexit_rev->to_room] == ch->in_room )
		{
			REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED);
			REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED);
			SET_BIT   ( pexit_rev->exit_info, EX_UNBARRED);
		}
		act( "$n causes the $d to dissolve.", ch, NULL, pexit->keyword, TO_ROOM );
		act( "You cause the $d to dissolve.", ch, NULL, pexit->keyword, TO_CHAR );
	}
	else
	{
		send_to_char("There's no valid target in that direction!\n\r", ch);
	}
	pop_call();
	return;
}

DO_SPELL(spell_fire_shield)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_fire_shield(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/10;
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_FIRESHIELD;
	affect_to_char( victim, &af );

	act( "$n bursts into flame!", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You burst into flame!\n\r", victim );

	pop_call();
	return;
}

DO_SPELL(spell_recharge)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;

	push_call("spell_recharge(%p,%p,%p,%p)",sn,level,ch,vo);

	if (obj->item_type == ITEM_STAFF || obj->item_type == ITEM_WAND)
	{
		if (obj->value[2] == obj->value[1] || obj->value[1] > (obj->pIndexData->value[1] * 4))
		{
			act( "$p bursts into flames, injuring you!", ch, obj, NULL, TO_CHAR );
			act( "$p bursts into flames, charring $n!", ch, obj, NULL, TO_ROOM);
			junk_obj(obj);
			damage(ch, ch, obj->level * 2, TYPE_UNDEFINED);

			pop_call();
			return;
		}

		if ( number_percent() <=2)
		{
			act( "$p glows with a blinding magical luminescence.", ch, obj, NULL, TO_CHAR);
			obj->value[1] *= 2;
			obj->value[2] = obj->value[1];

			pop_call();
			return ;
		}
		else if ( number_percent() <=5 )
		{
			act( "$p glows brightly for a few seconds...", ch, obj, NULL, TO_CHAR);
			obj->value[2] = obj->value[1];

			pop_call();
			return;
		}
		else if (number_percent() <= 10 )
		{
			act( "$p disintegrates into a void.", ch, obj, NULL, TO_CHAR);
			act( "$n's attempt at recharging fails, and $p disintegrates.", ch, obj, NULL, TO_ROOM);
			junk_obj(obj);

			pop_call();
			return;
		}
		else if (number_percent() <= 10 + level / 4)
		{
			send_to_char("Nothing happens.\n\r", ch);
			pop_call();
			return;
		}
		else
		{
			act( "$p feels warm to the touch.", ch, obj, NULL, TO_CHAR);
			--obj->value[1];
			obj->value[2] = obj->value[1];

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

		pop_call();
		return;
	}
	pop_call();
	return;
}

DO_SPELL(spell_vampiric_touch)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_vampiric_touch(%p,%p,%p,%p)",sn,level,ch,vo);

	if (check_hit(ch, victim, 0, gsn_vampiric_touch))
	{
		dam     = number_fuzzy(number_range(level*3, level*5));
		ch->hit = UMIN(ch->max_hit, ch->hit+dam/10);
		damage( ch, victim, dam, sn );
	}
	else
	{
		act( "$n's hand glows with dark energy, but fails to strike $s foe.", ch, NULL, victim, TO_ROOM );
		act( "The dark energies in your hand fail to strike $N.", ch, NULL, victim, TO_CHAR );
	}
	pop_call();
	return;
}

DO_SPELL(spell_windblast)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_windblast(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level*3, level*5);

	if ( saves_spell( level, ch, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_waterburst)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_waterburst(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level*2, level*6);

	if ( saves_spell( level, ch, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_mindblast)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_mindblast(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level*1, level*7);

	if ( saves_spell( level, ch, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_snake_dart)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;

	push_call("spell_mindblast(%p,%p,%p,%p)",sn,level,ch,vo);

	dam   = number_range(level*1, level*7);

	if (saves_spell(level, ch, victim))
	{
		dam /= 2;
	}
	else
	{
		if (number_bits(3) == 0 && !IS_AFFECTED(victim, AFF_POISON))
		{
			AFFECT_DATA af;

			af.type      = gsn_poison;
			af.location  = APPLY_AC;
			af.modifier  = level/2;
			af.duration  = level/20;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF_POISON;

			affect_to_char( victim, &af );

			send_to_char( "You feel poison coursing through your vains.\n\r", victim );
			if (ch != victim)
			{
				send_to_char( "They now feel your poison.\n\r", ch );
			}
		}
	}

	damage( ch, victim, dam, sn );

	pop_call();
	return;
}

DO_SPELL(spell_metamorphose_liquids)
{
	OBJ_DATA *obj = (OBJ_DATA *)vo;
	char arg3[MAX_INPUT_LENGTH];
	int liquid;

	push_call("spell_metamorphose_liquids(%p,%p,%p,%p)",sn,level,ch,vo);

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

	target_name = one_argument(target_name, arg3);
	target_name = one_argument(target_name, arg3);

	if (obj->item_type != ITEM_DRINK_CON)
	{
		send_to_char("That is not a drinkcontainer.\n\r",ch);
		pop_call();
		return;
	}

	if (!strlen(arg3))
	{
		send_to_char("Metamorphose to what kind of liquid?\n\r",ch);
		pop_call();
		return;
	}

	for (liquid = 0 ; liquid < LIQ_MAX ; liquid++)
	{
		if (!str_prefix(arg3, liq_table[liquid].liq_name))
		{
			break;
		}
	}

	if (liquid == LIQ_MAX)
	{
		send_to_char("There is no such liquid.\n\r", ch);
		pop_call();
		return;
	}

	if (obj->value[2] == liquid)
	{
		ch_printf(ch, "%s is already filled with %s\n\r", capitalize(obj->short_descr), liq_table[liquid].liq_name);
		pop_call();
		return;
	}
	else
	{
		ch_printf(ch, "You transform the %s in %s to %s.\n\r", liq_table[obj->value[2]].liq_name, obj->short_descr, liq_table[liquid].liq_name);
		obj->value[2] = liquid;
	}
	pop_call();
	return;
}

DO_SPELL(spell_detect_good)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_detect_good(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	af.type      = sn;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	send_to_char( "Traces of gold outline all good in plain sight.\n\r", victim );

	if (ch != victim)
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_firewalk)
{
	CHAR_DATA *victim = (CHAR_DATA *)vo;
	AFFECT_DATA af;

	push_call("spell_firewalk(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_NPC(victim))
	{
		send_to_char("You cannot cast this spell on mobs.\n",ch);
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF2_FIREWALK))
	{
		send_to_char("They are already affected.\n\r", ch);
		pop_call(); return;
	}
	af.type      = sn;
	af.duration  = level/2;
	af.location  = 0;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_FIREWALK;
	affect_to_char(victim, &af);

	act( "$n's feet glow a soft red.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your feet tingle.\n\r", victim );
	pop_call();
	return;
}
	
DO_SPELL(spell_divine_inspiration)
{
	CHAR_DATA *victim = (CHAR_DATA *)vo;
	AFFECT_DATA af;

	push_call("spell_divine_inspiration(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_NPC(victim))
	{
		send_to_char("You cannot cast this spell on mobs.\n",ch);
		pop_call();
		return;
	}

	if (IS_AFFECTED(victim, AFF2_DIVINE_INSPIRATION))
	{
		send_to_char("They are already affected.\n\r", ch);
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_INT;
	if (which_god(victim) != GOD_HYPNOS)
	{
		af.duration  = URANGE(2, level/10, 8);
		af.modifier  = 1 + (level > 49) + (level > 99);
	}
	else
	{
		af.duration = URANGE(8, level/5, 32);
		af.modifier = 1 + (level > 24) + (level > 49) + (level > 74) + (level > 99) + (level > 124);
	}
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_DIVINE_INSPIRATION;
	affect_to_char(victim, &af);

	act( "$n's eyes shine brightly.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your eyes shine brightly as divine inspiration sharpens your mind.\n\r", victim);
	pop_call();
	return;
}

DO_SPELL(spell_black_aura)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_black_aura(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	if (saves_spell(4*level/5, ch, victim))
	{
		act("Your shadow magic slithers around $N but fails to enshroud $M.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = number_range(0, level/70);
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	act( "$n is surrounded by a black aura.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "A bitter cloud of darkness envelopes you.\n\r", victim);

	pop_call();
	return;
}

DO_SPELL(spell_mana_shield)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_mana_shield(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/4;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	act( "A shield of sparkling blue energy coalesces around $n.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "A shield of sparkling blue energy coalesces around you.\n\r", victim);

	pop_call();
	return;
}

DO_SPELL(spell_magic_mirror)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_magic_mirror(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/4;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	act( "A shield of reflective magic coalesces around $n.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "A shield of reflective magic coalesces around you.\n\r", victim);

	pop_call();
	return;
}

DO_SPELL(spell_animate_object)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf, af;
	CHAR_DATA *mob;
	char animatename[MAX_INPUT_LENGTH];
	int i;

	push_call("spell_animte_object(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!IS_NPC(ch) && multi(ch, sn) == -1)
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (obj->carried_by != ch || obj->wear_loc != WEAR_NONE)
	{
		send_to_char( "You are not carrying that.\n\r", ch);
		pop_call();
		return;
	}

	if (obj->level > level)
	{
		send_to_char("You failed.\n\r", ch);
		pop_call();
		return;
	}

	if (get_pets(ch) > 0)
	{
		send_to_char("You have too many pets.\n\r", ch);
		pop_call();
		return;
	}

	mob = create_mobile( get_mob_index( MOB_VNUM_ILLUSION ) );
	char_to_room( mob, ch->in_room->vnum );

	mob->level				= obj->level;
	mob->npcdata->damnodice		= 0;
	mob->npcdata->damsizedice	= 0;
	mob->npcdata->damplus		= mob->level;

	if (obj->item_type == ITEM_WEAPON)
	{
		mob->max_hit			= 100;
	}
	else
	{
		mob->max_hit			= UMAX(200, mob->level * 20);
	}
	mob->hit					= mob->max_hit;

	for (animatename[0] = '\0', i = 0 ; obj->name[i] != '\0' ; i++)
	{
		if (obj->name[i] == ' ')
		{
			strcat(animatename, "^ ");
		}
		else
		{
			cat_sprintf(animatename, "%c", obj->name[i]);
		}
	}
	strcat(animatename, "^");

	RESTRING(mob->name,			animatename);
	RESTRING(mob->short_descr,	obj->short_descr);
	RESTRING(mob->long_descr,	obj->long_descr);
	RESTRING(mob->description,	obj->description);

	REMOVE_BIT(mob->act, ACT_RACE);
	REMOVE_BIT(mob->act, ACT_SMART);
	mob->sex			= SEX_NEUTRAL;
	mob->race			= RACE_HUMAN;
	mob->gold			= obj->cost/2;

	af.type		= sn;
	af.duration	= -1;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector	= 0;

	for (paf = obj->first_affect ; paf ; paf = paf->next)
	{
		switch (paf->location)
		{
			case APPLY_STR:
				mob->npcdata->damplus	+= paf->modifier * 10;
				break;
			case APPLY_DAMROLL:
				mob->npcdata->damplus	+= paf->modifier * 5;
				break;
			case APPLY_HIT:
			case APPLY_CON:
				mob->hit = mob->max_hit	 = UMAX(100, mob->max_hit + paf->modifier * 10);
				break;
			case APPLY_MANA:
			case APPLY_WIS:
				mob->mana = mob->max_mana = UMAX(100, mob->max_mana + paf->modifier * 10);
				break;
			case APPLY_MOVE:
				mob->move = mob->max_move = UMAX(100, mob->max_move + paf->modifier * 10);
				break;
			case APPLY_DEX:
				af.modifier	= paf->modifier * 20;
				af.location	= APPLY_AC;
				affect_to_char(mob, &af);
				break;
			case APPLY_AC:
				af.modifier	= paf->modifier * 10;
				af.location	= APPLY_AC;
				affect_to_char(mob, &af);
				break;
			case APPLY_HITROLL:
				mob->hitroll			+= paf->modifier * 5;
				break;
			case APPLY_SAVING_PARA:
			case APPLY_SAVING_ROD:
			case APPLY_SAVING_PETRI:
			case APPLY_SAVING_BREATH:
			case APPLY_SAVING_SPELL:
			case APPLY_INT:
				mob->saving_throw		+= paf->modifier * 5;
				break;
		}
	}

	for (paf = obj->pIndexData->first_affect ; paf ; paf = paf->next)
	{
		switch (paf->location)
		{
			case APPLY_STR:
				mob->npcdata->damplus	+= paf->modifier * 10;
				break;
			case APPLY_DAMROLL:
				mob->npcdata->damplus	+= paf->modifier * 5;
				break;
			case APPLY_HIT:
			case APPLY_CON:
				mob->hit = mob->max_hit	 = UMAX(100, mob->max_hit + paf->modifier * 10);
				break;
			case APPLY_MANA:
			case APPLY_WIS:
				mob->mana = mob->max_mana = UMAX(100, mob->max_mana + paf->modifier * 10);
				break;
			case APPLY_MOVE:
				mob->move = mob->max_move = UMAX(100, mob->max_move + paf->modifier * 10);
				break;
			case APPLY_DEX:
				af.modifier	= paf->modifier * 20;
				af.location	= APPLY_AC;
				affect_to_char(mob, &af);
				break;
			case APPLY_AC:
				af.modifier	= paf->modifier * 10;
				af.location	= APPLY_AC;
				affect_to_char(mob, &af);
				break;
			case APPLY_HITROLL:
				mob->hitroll			+= paf->modifier * 5;
				break;
			case APPLY_SAVING_PARA:
			case APPLY_SAVING_ROD:
			case APPLY_SAVING_PETRI:
			case APPLY_SAVING_BREATH:
			case APPLY_SAVING_SPELL:
			case APPLY_INT:
				mob->saving_throw		+= paf->modifier * 5;
				break;
		}
	}

	if (obj->item_type == ITEM_ARMOR)
	{
		af.modifier	= obj->value[0] * -10;
		af.location	= APPLY_AC;
		affect_to_char(mob, &af);
	}
	if (IS_OBJ_STAT(obj, ITEM_INVIS))
	{
		SET_BIT(mob->affected_by, AFF_IMP_INVISIBLE);
	}
	if (IS_OBJ_STAT(obj, ITEM_BLESS))
	{
		mob->alignment = 1000;
	}
	if (IS_OBJ_STAT(obj, ITEM_EVIL))
	{
		mob->alignment = -1000;
	}

	while (obj->first_content != NULL)
	{
		obj_to_char(obj->first_content, mob);
	}

	act("$N flies from your hand and bows before you.", ch, NULL, mob, TO_CHAR);
	act("$N flies from $n's hand and bows before $m.",  ch, NULL, mob, TO_ROOM);

	SET_BIT(mob->affected_by, AFF_CHARM );
	add_follower( mob, ch );

	if (IS_SET(obj->extra_flags, ITEM_MOUNT))
	{
		SET_BIT( mob->act, ACT_MOUNT );
	}

	REMOVE_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
	REMOVE_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
	REMOVE_BIT(obj->extra_flags, ITEM_ANTI_NEUTRAL);

	SET_BIT(obj->extra_flags, ITEM_ETHEREAL);
	SET_BIT(obj->extra_flags, ITEM_NOREMOVE);
	SET_BIT(obj->extra_flags, ITEM_NODROP);
	SET_BIT(obj->extra_flags, ITEM_INVENTORY);

	switch (obj->item_type)
	{
		case ITEM_WEAPON:
			obj_to_char(obj, mob);
			equip_char(mob, obj, WEAR_WIELD);
			break;
		case ITEM_LIGHT:
			obj_to_char(obj, mob);
			equip_char(mob, obj, WEAR_LIGHT);
			break;
		default:
			if (IS_SET(obj->wear_loc, ITEM_WEAR_SHIELD))
			{
				obj_to_char(obj, mob);
				equip_char(mob, obj, WEAR_SHIELD);
			}
			else
			{
				junk_obj(obj);
			}
			break;
	}
	pop_call();
	return;
}

DO_SPELL(spell_mana_shackles)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_mana_shackles(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char( "They are already shackled.\n\r", ch );
		pop_call();
		return;
	}

	if ( saves_spell( level, ch, victim ) )
	{
		act("Strings of lightning shoot from your hands but fail to entangle $N.",  ch, NULL, victim, TO_CHAR);
		act("Strings of lightning shoot from $n's hands but fail to entangle you.", ch, NULL, victim, TO_VICT);
		act("Strings of lightning shoot from $n's hands but fail to entangle $N.",  ch, NULL, victim, TO_NOTVICT);
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level/15;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	affect_to_char( victim, &af );

	act("Strings of lightning shoot from your hands, entangling $N.",  ch, NULL, victim, TO_CHAR);
	act("Strings of lightning shoot from $n's hands, entangling you.", ch, NULL, victim, TO_VICT);
	act("Strings of lightning shoot from $n's hands, entangling $N.",  ch, NULL, victim, TO_NOTVICT);

	pop_call();
	return;
}

DO_SPELL(spell_earthbind)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_earthbind(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF2_EARTHBIND))
	{
		send_to_char("They are already bound to the earth.\n\r", ch);
		pop_call();
		return;
	}

	if (saves_spell(level, ch, victim))
	{
		act("Your shadow magic slithers around $N but fails to bind $M.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	send_to_char("You have been bound to the earth.\n\r", victim);

	if (ch != victim)
	{
		send_to_char("You bind them to the earth.\n\r", ch);
	}

	if (CAN_FLY(victim))
	{
		act("You fall to the ground.", ch, NULL, victim, TO_VICT);
		act("$n falls to the ground.", victim, NULL, ch, TO_ROOM);

		damage(ch, victim, number_range(level, level*3), sn);
	}

	affect_strip(victim, gsn_fly);

	af.type      = sn;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.duration  = 1+level/5;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_EARTHBIND;
	affect_to_char( victim, &af );

	pop_call();
	return;
}

DO_SPELL(spell_quicken)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_quicken(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF2_QUICKEN))
	{
		send_to_char("They are already quick of mind.\n\r", ch);
		pop_call();
		return;
	}

	act( "$n's eyes glitter as time wrinkles then slows to quicken $s mind.", victim, NULL, NULL, TO_ROOM );

	af.type      = sn;
	af.duration  = 12;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_QUICKEN;
	affect_to_char( victim, &af );

	send_to_char( "Time wrinkles then slows as your thoughts start racing.\n\r", victim );

	if (ch != victim)
	{
		send_to_char( "Ok.\n\r", ch );
	}
	pop_call();
	return;
}

DO_SPELL(spell_torrid_balm)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_torrid_balm(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(victim, AFF2_TORRID_BALM))
	{
		send_to_char( "They are already engulfed by fire.\n\r", ch );
		pop_call();
		return;
	}

	if (saves_spell(level, ch, victim))
	{
		send_to_char( "Flames ignite from your hands, but fail to surround your foe.\n\r", ch );
		pop_call();
		return;
	}

	af.type      = sn;
	af.duration  = level / 20;
	af.location  = IS_NPC(victim) ? APPLY_AC : APPLY_DEX;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_TORRID_BALM;
	affect_to_char(victim, &af );

	if (ch != victim)
	{
		act("Flames ignite from your hands, engulfing $N.",  ch, NULL, victim, TO_CHAR);
		act("Flames ignite from $n's hands, engulfing you.", ch, NULL, victim, TO_VICT);
		act("Flames ignite from $n's hands, engulfing $N.",  ch, NULL, victim, TO_NOTVICT);
	}
	else
	{
		act("Flames ignite from your hands, engulfing yourself.", ch, NULL, victim, TO_CHAR);
		act("Flames ignite from $n's hands, engulfing $mself.",   ch, NULL, victim, TO_NOTVICT);
	}
	pop_call();
	return;
}

DO_SPELL(spell_song_of_the_seas)
{
	CHAR_DATA *victim = (CHAR_DATA *)vo;
	AFFECT_DATA af;

	push_call("spell_song_of_the_seas(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char("They are already affected.\n\r", ch);
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_WIS;
	if (which_god(victim) != GOD_ULMO)
	{
		af.duration  = URANGE(2, level/10, 8);
		af.modifier  = 1 + (level > 49) + (level > 99);
	}
	else
	{
		af.duration = URANGE(8, level/5, 32);
		af.modifier = 1 + (level > 24) + (level > 49) + (level > 74) + (level > 99) + (level > 124);
	}
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char(victim, &af);

	send_to_char( "Your eyes shine sagaciously as the song of the seas guides your path.\n\r", victim);
	act( "$n's eyes shine sagaciously.", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_earthen_spirit)
{
	CHAR_DATA *victim = (CHAR_DATA *)vo;
	AFFECT_DATA af;

	push_call("spell_earthen_spirit(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char("They are already affected.\n\r", ch);
		pop_call();
		return;
	}

	af.type      = sn;
	af.location  = APPLY_CON;
	if (which_god(victim) != GOD_GAIA)
	{
		af.duration  = URANGE(2, level/10, 8);
		af.modifier  = 1 + (level > 49) + (level > 99);
	}
	else
	{
		af.duration = URANGE(8, level/5, 32);
		af.modifier = 1 + (level > 24) + (level > 49) + (level > 74) + (level > 99) + (level > 124);
	}
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	affect_to_char(victim, &af);

	send_to_char("The spirit of the earth swirls around you.\n\r", victim);
	act( "The spirit of the earth swirls around $n", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_icicle_armor)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_icicle_armor(%p,%p,%p,%p)",sn,level,ch,vo);

	if (is_affected(victim, sn))
	{
		send_to_char("You are already encased in an icicle armor.\n\r", ch);
		pop_call();
		return;
	}
	af.type		= sn;
	af.duration	= level;
	af.modifier	= -1 * UMAX(1, level / 15) * 5;
	af.location	= APPLY_AC;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector	= AFF2_ICICLE_ARMOR;

	affect_to_char(victim, &af);

	send_to_char("Spikes of ice rip through your skin, encasing you in armor.\n\r", victim);
	act("Spikes of ice rip through $n's skin, encasing $m in armor.", victim, NULL, NULL, TO_ROOM );

	pop_call();
	return;
}

DO_SPELL(spell_flamewave)
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	EXIT_DATA *pexit;
	int door, temp_vnum;

	push_call("spell_flamewave(%p,%p,%p,%p)",sn,level,ch,vo);

	/*
		no flamewave under water
	*/

	if (ch->in_room->sector_type == SECT_UNDER_WATER)
	{
		send_to_char("The water boils around you.\n\r",ch);
		pop_call();
		return;
	}

	switch (ch->in_room->sector_type)
	{
		case SECT_LAKE:
		case SECT_RIVER:
		case SECT_OCEAN:
			level /= 2;
	}

	act("Tongues of fire and flame spew forth by your command!", ch, NULL, NULL, TO_CHAR);
	act("Tongues of fire and flame spew forth by $n's command.", ch, NULL, NULL, TO_ROOM);

	temp_vnum = ch->in_room->vnum;

	for (door = 0 ; door <= 5 ; door++)
	{
		if ((pexit = get_exit(temp_vnum, door)) && pexit->to_room != temp_vnum)
		{
			ch->in_room = room_index[pexit->to_room];
			act("The air about you sears with heat.", ch, NULL, NULL, TO_ROOM);
		}
	}
	ch->in_room = room_index[temp_vnum];

	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;

		if (!can_mass_cast(ch, vch))
		{
			continue;
		}
		damage( ch, vch, level + dice(1, 50), sn );
	}
	pop_call();
	return;
}

DO_SPELL(spell_flame_blade)
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_flame_blade(%p,%p,%p,%p)",sn,level,ch,vo);

	if (obj->item_type != ITEM_WEAPON)
	{
		act("You can only imbue weapons with fire.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (IS_SET(obj->extra_flags, ITEM_BURNING))
	{
		act("$p is already burning.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (number_fuzzy(obj->level) >= level)
	{
		act("$p glows brightly, then returns to normal.", ch, obj, NULL, TO_CHAR);
		act("$p glows brightly, then returns to normal.", ch, obj, NULL, TO_ROOM);
		pop_call();
		return;
	}

	SET_BIT(obj->extra_flags, ITEM_MODIFIED);
	SET_BIT(obj->extra_flags, ITEM_MAGIC);

	act("Blue flames ignite from $p.", ch, obj, NULL, TO_CHAR);
	act("Blue flames ignite from $p.", ch, obj, NULL, TO_ROOM);

	af.type      = sn;
	af.duration  = level * 5;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_BURNING;

	affect_to_obj(obj, &af);

	pop_call();
	return;
}

DO_SPELL(spell_totem)
{
	OBJ_DATA *totem;

	push_call("spell_totem(%p,%p,%p,%p)",sn,level,ch,vo);

	for (totem = ch->in_room->first_content ; totem ; totem = totem->next_content)
	{
		if (totem->item_type == ITEM_TOTEM)
		{
			send_to_char("There is already a totem in this room.\n\r", ch);
			pop_call();
			return;
		}
	}

	switch (ch->in_room->sector_type)
	{
		case SECT_AIR:
		case SECT_ETHEREAL:
		case SECT_ASTRAL:
		case SECT_LAKE:
		case SECT_RIVER:
		case SECT_OCEAN:
			send_to_char("You cannot cast a totem in this room.\n\r", ch);
			pop_call();
			return;
	}

	totem = create_object( get_obj_index( OBJ_VNUM_TOTEM ), 0 );
	totem->timer = level;
	totem->level = level;

	act( "A totem rises up from the ground.", ch, NULL, NULL, TO_CHAR );
	act( "A totem rises up from the ground.", ch, NULL, NULL, TO_ROOM );

	obj_to_room( totem, ch->in_room->vnum );

	switch (tolower(target_name[0]))
	{
		case 'c':
			totem->value[0] = slot_lookup(translate_bits("SPELL_CURE_POISON"));
			totem->value[1] = slot_lookup(translate_bits("SPELL_CURE_BLINDNESS"));
			totem->value[2] = slot_lookup(translate_bits("SPELL_REMOVE_CURSE"));
			totem->value[3] = slot_lookup(translate_bits("SPELL_CURE_CRITICAL"));
			break;

		case 'p':
			totem->value[0] = slot_lookup(translate_bits("SPELL_GIANT_STRENGTH"));
			totem->value[1] = slot_lookup(translate_bits("SPELL_ENHANCED_HEAL"));
			totem->value[2] = slot_lookup(translate_bits("SPELL_BLESS"));
			if (ch->alignment < 0)
			{
				totem->value[3] = slot_lookup(translate_bits("SPELL_PROTECTION_GOOD"));
			}
			else
			{
				totem->value[3] = slot_lookup(translate_bits("SPELL_PROTECTION_EVIL"));
			}
			break;
		default:
			totem->value[0] = slot_lookup(translate_bits("SPELL_HEAL"));
			totem->value[1] = slot_lookup(translate_bits("SPELL_CURE_LIGHT"));
			totem->value[2] = slot_lookup(translate_bits("SPELL_CURE_SERIOUS"));
			totem->value[3] = slot_lookup(translate_bits("SPELL_CURE_CRITICAL"));
			break;
	}
	pop_call();
	return;
}

/*
 * 11 sept 2004, Michiel Lange
 * First stonefist implementation
 */

DO_SPELL(spell_steelhand)
{
	CHAR_DATA *victim=(CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("spell_steelhand(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( is_affected( victim, sn ) )
	{
		send_to_char( "They are already affected.\n\r", ch );
		pop_call();
		return;
	}
	
	af.type      = sn;
	af.duration  = level/2;
	af.location  = 0;
	af.modifier  = ((level/10)+1) * ((level/25)+6);
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_STEELHAND;
	affect_to_char(victim, &af);

	act( "$n's hands become razorsharp steel.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your hands turn to razorsharp steel blades.\n\r", victim );
	pop_call();
	return;
}

/* The sloth spell decreases the victim's agility for a certain amount of time 
   Created by Hypnos 20041114. */
DO_SPELL(spell_sloth)
{
	CHAR_DATA *victim=(CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("spell_sloth(%d,%d,%p,%p,%d)", sn, level, ch, vo, target);
	
	if ( IS_AFFECTED( victim, AFF2_SLOTH ) )
	{
		if(victim == ch)
		{
			ch_printf(ch, "You are already affected by the sloth spell.\n\r");
		}
		else
		{
			ch_printf(ch, "%s is already affected by the sloth spell.\n\r", capitalize(get_name(victim)));
		}
		
		pop_call();
		return;
	}
	
	af.type = sn;
	
	if (!IS_NPC(victim) && IS_IMMORTAL(victim))
	{
		ch_printf(ch, "Immortal beings are immune to the sloth spell.\n\r");
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		af.duration = number_fuzzy(level / 10);
	}
	else
	{
		af.duration = number_fuzzy(level / 15);
	}

	af.location = APPLY_DEX;
	af.modifier = -(1 + ((level / 30)) * ((level / 10) + 1));
	af.bittype = AFFECT_TO_CHAR;
	af.bitvector = AFF2_SLOTH;
	
	affect_to_char(victim, &af);

	act( "$n's agility dwindles.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your agility dwindles as sloth takes hold of you.\n\r", victim);
	pop_call();
	return;
}

/* The spell "a touch of idiocy" decrease's the poor victim's 
   Int and Wis scores by 1d6 
   Created by Hypnos 20041115 */
DO_SPELL(spell_touch_of_idiocy)
{
	CHAR_DATA *victim=(CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("spell_touch_of_idiocy(%d,%d,%p,%p,%d)", sn, level, ch, vo, target);
	
	if ( IS_AFFECTED( victim, AFF2_TOUCHOFIDIOCY ) )
	{
		if(victim == ch)
		{
			ch_printf(ch, "You are already affected by the touch of idiocy spell.\n\r");
		}
		else
		{
			ch_printf(ch, "%s is already affected by the touch of idiocy spell.\n\r", capitalize(get_name(victim)));
		}
		
		pop_call();
		return;
	}
	
	af.type = sn;
	
	if (!IS_NPC(victim) && IS_IMMORTAL(victim))
	{
		ch_printf(ch, "The infinite wisdom and intellect of the Immortals are immune to the touch of idocy spell.\n\r");
		pop_call();
		return;
	}

	af.duration = number_fuzzy(level / 8);

	af.location = APPLY_INT;
	af.modifier = -1 - dice(level / 25, 6);
	af.bittype = AFFECT_TO_CHAR;
	af.bitvector = AFF2_TOUCHOFIDIOCY;
	
	affect_to_char(victim, &af);

	af.location = APPLY_WIS;
	af.modifier = -1 - dice(level / 25, 6);
	affect_to_char(victim, &af);

	act( "A powerful curse descends upon $s.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You suddenly feel a lot less certain of yourself.\n\r", victim);
	pop_call();
	return;
}