daleken/
daleken/data/notes/
daleken/data/player/
daleken/data/system/poses/
daleken/doc/Homepage/images/
daleken/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc 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{rfeldt,	 ||
    || Tom Madsen, and Katja Nyboe.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  Much time and thought has gone into this software and	 ||
    || you are benefitting. We hope that you share your changes too.	 ||
    || What goes around, comes around.					 ||
    || ----------------------------------------------------------------- ||
    ||                             magic_off.c                           ||
    || Offensive spells code.                                            ||
 *_/<>\_________________________________________________________________/<>\_*/


#include <math.h>
#include "mud.h"
#include "event.h"

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


int magic_damage	args( ( int level, int power ) );


/*
 * Calculate the base damage dealt by a spell, given the level
 * of the cast and the relative power of that particular spell.
 * This function serves as a guide to the power of spells.
 *
 * Concept:
 *    base damage value based on power;
 *    increase in damage for every level up to first threshold;
 *    half the increase up to next threshold;
 *    after that the damage doesn't increase.
 * Power 9 and 10 are special cases for the top threshold.
 */
int magic_damage( int level, int power )
{
    int dam;
    int threshold1 = power * 5;
    int threshold2;

    dam = power << 2 | 2;

    if( power == 9 )
    {
	threshold1 = 95;
	threshold2 = 150;
    }
    else if( power >= 10 )
    {
	threshold1 = 150;
	threshold2 = 250;
    }
    else
	threshold2 = threshold1 + (int)pow( (double)power + 5.0 / 2.0, 1.5 );

    if( level > threshold2 )
    {
	dam += level - threshold2;
	level = threshold2;
    }

    if( level > threshold1 )
    {
	dam += ( level - threshold1 ) * power;
	level = threshold1;
    }

    dam += level * power / 2;

    if( number_bits( 6 ) == 0 )
	dam <<= 1;

    return number_range( dam >> 1, dam );
}


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

    dam = magic_damage( level, 7 );
    dam = dam * victim->hit * 4 / victim->max_hit / 3;
    damage( ch, victim, dam, sn, WEAR_NONE );

    return;
}


/*
 * NPC spells.
 */
void spell_acid_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj_lose;
    OBJ_DATA *obj_next;
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam;
    int hpch;

    if( number_percent( ) < level && !saves_spell( level, victim, ch, sn ) )
    {
	for( obj_lose = victim->carrying; obj_lose; obj_lose = obj_next )
	{
	    int iWear;

	    obj_next = obj_lose->next_content;
	    if( obj_lose->deleted )
		continue;

	    if( number_bits( 3 ) != 0 )
		continue;

	    switch( obj_lose->item_type )
	    {
	    case ITEM_ARMOUR:
		if( obj_lose->value[0] > 0 )
		{
		    /* Correction on math by IvoryTiger */
		    act( "$p is pitted and etched!",
			 victim, obj_lose, NULL, TO_CHAR );
		    if( ( iWear = obj_lose->wear_loc ) != WEAR_NONE )
			victim->armour += apply_ac( victim, obj_lose, iWear );
		    if( number_bits( 2 ) == 0 )
			obj_lose->value[0] -= 1;
		    obj_lose->cost = 0;
		    if( iWear != WEAR_NONE )
			victim->armour -= apply_ac( victim, obj_lose, iWear );
		}
		mod_item_condition( victim, obj_lose, number_fuzzy( 1 ) );
		break;

	    case ITEM_TREASURE:
		act( "$p is etched and ruined!",
		     victim, obj_lose, NULL, TO_CHAR );
		obj_lose->cost = 0;
		mod_item_condition( victim, obj_lose, number_fuzzy( 1 ) );
		break;

	    case ITEM_CONTAINER:
	    case ITEM_PORTAL:
	    case ITEM_FURNITURE:
		act( "$p fumes and dissolves!",
		     victim, obj_lose, NULL, TO_CHAR );
		mod_item_condition( victim, obj_lose, number_fuzzy( 1 ) );
		break;
	    default:
		break;
	    }
	}
    }

    hpch = UMAX( 10, ch->hit );
    dam = number_range( hpch / 8 + 1, hpch / 4 );
    damage( ch, victim, dam, sn, WEAR_NONE );

    return;
}


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

    act( "&cYou summon the swift powers of air to pummel $N!",
	 ch, NULL, victim, TO_CHAR );
    act( "&cThe air suddenly begins pounding on you from all sides!",
	 ch, NULL, victim, TO_VICT );
    act( "&c$N summons the swift powers of air to pummel $n!",
	 ch, NULL, victim, TO_NOTVICT );

    damage( ch, victim, magic_damage( level, 11 ), sn, WEAR_NONE );
    return;
}


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

    act( "$n chuckle$% as a stone strikes $N.", ch, NULL, victim, TO_ALL );

    damage( ch, victim, magic_damage( level, 4 ), sn, WEAR_NONE );
    return;
}


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

    if( IS_AFFECTED( victim, AFF_BLIND )
	|| saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "You have failed.\n\r", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = 1 + level;
    af.location = APPLY_HITROLL;
    af.modifier = -4 - level / 25;
    vset( af.bitvector, AFF_BLIND );
    affect_to_char( victim, &af, NULL );

    send_to_char( "You are blinded!\n\r", victim );
    act( "$n is blinded!", victim, NULL, NULL, TO_ROOM );
    return;
}


void spell_blizzard( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;

    act( "$n calls churning ice from the sky!", ch, NULL, NULL, TO_ROOM );
    act( "You call churning ice from the sky!", ch, NULL, NULL, TO_CHAR );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;

	damage( ch, vch, magic_damage( level, 5 ), sn, WEAR_NONE );
    }
    return;
}


void spell_call_lightning( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;

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

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

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

    for( vch = char_list; vch; vch = vch->next )
    {
	if( vch->deleted || !vch->in_room )
	    continue;
	if( vch->in_room == ch->in_room )
	{
	    if( vch != ch && !is_safe( ch, vch )
		&& ( !IS_NPC( ch ) || !IS_NPC( vch ) ) )
		damage( ch, vch, magic_damage( level, 6 ), sn, WEAR_NONE );
	    continue;
	}

	if( vch->in_room->area == ch->in_room->area
	    && IS_OUTSIDE( vch )
	    && IS_AWAKE( vch ) )
	    send_to_char( "Lightning flashes in the sky.\n\r", vch );
    }

    return;
}


void spell_cause_critical( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 3 ), sn, WEAR_NONE );
    return;
}


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

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

    if( get_trust( ch ) > LEVEL_HERO && get_trust( ch ) < L_SEN )
    {
	send_to_char( "There is no need for you to have a charmed mobile\n\r",
		     ch );
	log_string( "%s charming", ch->name );
	return;
    }

    if( IS_AFFECTED( victim, AFF_CHARM )
	|| IS_AFFECTED( ch, AFF_CHARM )
	|| level < victim->level
	|| saves_spell( level, victim, ch, sn ) )
	return;

    if( victim->master )
	stop_follower( victim );
    add_follower( victim, ch );

    af.type = sn;
    af.level = level;
    af.duration = number_fuzzy( level / 4 );
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_CHARM );
    if( !affect_to_char( victim, &af, NULL ) )
	return;

    send_to_char( "Ok.\n\r", ch );
    act( "Isn't $n just so nice?", ch, NULL, victim, TO_VICT );
    return;
}


void spell_colour_spray( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch, *vch_next;
    AFFECT_DATA af;
    int dam;

    af.type = sn;
    af.level = level;
    af.location = APPLY_HITROLL;
    af.modifier = -4;
    af.duration = 5;
    vset( af.bitvector, AFF_BLIND );

    send_to_room( "Multi-coloured shards of light spray around the room!",
		  ch->in_room );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;

	if( IS_SET( race_table[vch->race].race_abilities, RACE_NO_SUN ) )
	    dam = magic_damage( level, 4 );
	else
	    dam = magic_damage( level + 5, 5 );

	if( !saves_spell( level, vch, ch, sn ) && !is_safe( ch, vch ) )
	    affect_to_char( vch, &af, NULL );

	damage( ch, vch, dam, sn, WEAR_NONE );
    }

    return;
}


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

    if( ch && !IS_NPC( ch ) && IS_EVIL( ch ) )
    {
	send_to_char( "You are too EVIL to cast this.\n\r", ch );
	return;
    }

    if( !ch )
	ch = victim;

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

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

    dam = number_range( victim->hit / 20, victim->hit / 16 );
    damage( ch, victim, dam, sn, WEAR_NONE );

    return;
}


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

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_HITROLL;
    af.modifier = -5 - level / 50;
    vset( af.bitvector, AFF_CONFUSION );
    if( !affect_to_char( victim, &af, NULL ) )
	return;
    act( "$n suddenly forget$% what $e was doing and $e look$% totally bewildered.",
	 victim, NULL, NULL, TO_ROOM );
    return;
}


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

    /* botch job for now, just check floaters */
    if( !get_eq_char( ch, WEAR_FLOAT_L )
	&& !get_eq_char( ch, WEAR_FLOAT_R ) )
    {
	send_to_char( "You must be carrying a floating light source.\n\r", ch );
	return;
    }

    damage( ch, victim, magic_damage( level, 4 ), sn, WEAR_NONE );

    return;
}


/* spell somewhat follows the spell from Greed MUD */
void spell_cream_pie( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam;
    AFFECT_DATA af;

    act( "You hurl a cream pie at $N.", ch, NULL, victim, TO_CHAR );
    act( "$n produces a cream pie from somewhere and flings it at $N.",
	 ch, NULL, victim, TO_ROOM );

    if( number_bits( 5 ) > 30 + level * 3 - victim->level * 3 )
    {
	send_to_char( "Your pie flies wide of its mark.\n\r", ch );
	act( "The pie flies wide of its mark.", ch, NULL, victim, TO_ROOM );
	return;
    }
    dam = magic_damage( level, 7 );
    if( number_bits( 6 ) > get_curr_dex( victim ) + victim->level - level )
    {
	af.type = sn;
	af.level = level;
	af.duration = number_fuzzy( 2 );
	af.location = APPLY_DAMROLL;
	af.modifier = -5 - level / 20;
	vset( af.bitvector, AFF_BLIND );
	affect_to_char( victim, &af, NULL );
	act( "The pie lands squarely on $O dial, blinding $M.",
	     ch, NULL, victim, TO_ALL );
    }
    else	/* This spell is unique, it has very bad damage when it
		   misses, not just relying on the normal reductions. */
	dam /= 2;
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


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

    if( is_affected( victim, sn ) || saves_spell( level + 5, victim, ch, sn ) )
    {
	send_to_char( "You have failed.\n\r", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_HITROLL;
    af.modifier = -2 - level / 20;
    vzero( af.bitvector );
    affect_to_char( victim, &af, NULL );

    af.location = APPLY_MAGIC_RESIST;
    af.modifier = -2 - level / 20;
    affect_to_char( victim, &af, NULL );

    if( ch != victim )
	send_to_char( "Ok.\n\r", ch );
    send_to_char( "You feel unclean.\n\r", victim );
    return;
}


void spell_cyclone( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch, *vch_next;

    act( "$n summon$% a swirling cyclone to attack $s enemies.",
	 ch, NULL, NULL, TO_ALL );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	damage( ch, vch, magic_damage( level, 7 ), sn, WEAR_NONE );
    }
    return;
}


void spell_dancing_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = ch->fighting;
    OBJ_DATA *wield;
    bool hadnomiss = FALSE;

    if( IS_NPC( ch ) )
	return;
    if( !victim )
    {
	send_to_char( "You must be fighting to cast this spell.\n\r", ch );
	return;
    }
    wield = get_eq_char( ch, WEAR_WIELD_R );
    if( !wield )
	wield = get_eq_char( ch, WEAR_WIELD_L );
    if( !wield )
	wield = get_eq_char( ch, WEAR_WIELD_DOUBLE );
    if( !wield )
    {
	send_to_char( "You must be wielding a weapon.\n\r", ch );
	return;
    }
    if( !can_drop_obj( ch, wield ) )
    {
	send_to_char( "You can't let go of it.\n\r", ch );
	return;
    }

    if( IS_AFFECTED( ch, AFF_NEVERMISS ) )
	hadnomiss = TRUE;
    xSET_BIT( ch->affected_by, AFF_NEVERMISS );

    act( "$n send$% $p out to attack $N.", ch, wield, victim, TO_ALL );
    multi_hit( ch, victim, sn );
    if( ch->fighting != victim )
    {
	act( "$p returns to $o hand.", ch, wield, NULL, TO_ALL );
    }
    else
    {
	act( "$p drops to the ground lifeless.", ch, wield, victim, TO_ALL );
	unequip_char( ch, wield );
	obj_from_char( wield );
	obj_to_room( wield, ch->in_room );
    }
    if( !hadnomiss )
	xREMOVE_BIT( ch->affected_by, AFF_NEVERMISS );
    return;
}


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

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

    if( ch != victim )
    {
	act( "$n dies.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You die!\n\r", victim );
	raw_kill( ch, victim );
    }
    else
	send_to_char( "You failed.\n\r", ch );
    return;
}


void spell_death_field( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch, *vch_next;
    int dam;
    int hpch;

    if( !IS_EVIL( ch ) )
    {
	send_to_char( "You are not evil enough to do that!\n\r", ch );
	return;
    }

    act( "A black haze emanates from $n!", ch, NULL, ch, TO_ALL );

    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;

	hpch = URANGE( 10, ch->hit, 999 );
	if( !saves_spell( level, vch, ch, sn )
	    && ( level <= vch->level + 5
		&& level >= vch->level - 5 ) )
	{
	    dam = 7;	/* Enough to compensate for sanct. & prot. and resil. */
	    vch->hit = 1;
	    update_pos( vch );
	    act( "The haze envelops $N!", ch, NULL, vch, TO_ALL );
	}
	else
	    dam = number_range( hpch / 16 + 1, hpch / 8 );

	damage( ch, vch, dam, sn, WEAR_NONE );
    }
    return;
}


void spell_detonate( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    CHAR_DATA *vch, *vch_next;
    OBJ_DATA *obj, *vobj = NULL;
    int dam;
    int count = 0;
    bool explode = FALSE;

    dam = magic_damage( level, 9 );
    if( !saves_spell( level, victim, ch, sn ) )
    {
	for( obj = victim->carrying; obj; obj = obj->next_content )
	{
	    if( !obj->deleted && number_range( 0, ++count ) == 0 )
		vobj = obj;
	}
	if( vobj )
	{
	    if( number_bits( 3 ) == 0 )
	    {
		explode = TRUE;
		act( "&r$n loses control of the detonation!&n",
		    ch, NULL, NULL, TO_ROOM );
		send_to_char( "&rYou lost control of the detonation!&n\n\r",
			     ch );
		dam += dam / 2;
	    }
	    act( "$p detonates in a blinding flash!",
		 victim, vobj, NULL, TO_ALL );
	    obj_from_char( vobj );
	    extract_obj( vobj );
	}
	else
	    dam /= 2;
    }
    else
	dam /= 2;

    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted )
	    continue;
	if( vch == victim )
	    damage( ch, vch, dam, sn, WEAR_NONE );
	else if( explode )
	    damage( ch, vch, dam * 2 / 3, sn, WEAR_NONE );
    }
    return;
}


void spell_disintegrate( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    OBJ_DATA *obj_lose;
    OBJ_DATA *obj_next;
    int dam;

    act( "&KA beam of iridescant black light lances from $o finger at $N!",
	 ch, NULL, victim, TO_ALL );
    if( number_percent( ) < 2 * level
	&& !saves_spell( level, victim, ch, sn ) )
	for( obj_lose = victim->carrying; obj_lose; obj_lose = obj_next )
	{
	    obj_next = obj_lose->next_content;
	    if( obj_lose->deleted || number_bits( 3 ) != 0 )
		continue;

	    act( "$p disintegrates!", victim, obj_lose, NULL, TO_CHAR );
	    act( "$p disintegrates!", victim, obj_lose, NULL, TO_CANSEE );
	    extract_obj( obj_lose );
	}

    dam = magic_damage( level, 10 );
    if( !IS_NPC( ch ) && !saves_spell( level, victim, ch, sn )
	&& number_range( 0, 200 - ch->pcdata->learned[sn] ) == 0 )
	    dam *= 4;
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


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

    if( victim == ch )
    {
	send_to_char( "Dominate yourself?  You're weird.\n\r", ch );
	return;
    }

    if( IS_AFFECTED( victim, AFF_CHARM )
	|| IS_AFFECTED( ch, AFF_CHARM )
	|| level < victim->level
	|| saves_spell( level, victim, ch, sn ) )
	return;

    if( victim->master )
	stop_follower( victim );
    add_follower( victim, ch );

    af.type = sn;
    af.level = level;
    af.duration = number_fuzzy( level / 4 );
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_CHARM );
    affect_to_char( victim, &af, NULL );

    act( "Your will dominates $N!", ch, NULL, victim, TO_CHAR );
    act( "Your will is dominated by $n!", ch, NULL, victim, TO_VICT );
    return;
}


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

    dam = magic_damage( level, 5 );
    if( !saves_spell( level, victim, ch, sn ) )
    {
	af.type = sn;
	af.level = level;
	af.location = APPLY_BODY_TEMP;
	af.modifier = -25 - level / 5;
	vzero( af.bitvector );
	af.duration = 10 + level / 5;
	affect_to_char( victim, &af, NULL );
	send_to_char( "You feel a chill reach over your entire body.\n\r", victim );
    }

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


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

    if( !IS_SET( victim->body_parts, BODY_PART_WINGS )
	&& !xIS_SET( victim->affected_by, AFF_FLYING ) )
    {
	send_to_char( "They are not flying.\n\r", ch );
	return;
    }
    if( saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }
    affect_strip( victim, skill_lookup( "fly" ) );
    affect_strip( victim, skill_lookup( "levitation" ) );
    REMOVE_BIT( victim->body_parts, BODY_PART_WINGS );
    xREMOVE_BIT( victim->affected_by, AFF_FLYING );
    act( "$n suddenly crashes to the ground.", victim, NULL, NULL, TO_ROOM );
    send_to_char( "You no longer fly.\n\r", victim );
    dam = magic_damage( level, 3 );
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


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

    act( "&yYou call upon the weighty earth powers to shatter $N!",
	 ch, NULL, victim, TO_CHAR );
    act( "&yYour bones creak under the enormouse pressure of $o earth power!",
	 ch, NULL, victim, TO_VICT );
    act( "&y$n calls on earth powers and $N is crushed by $S own weight!",
	 ch, NULL, victim, TO_NOTVICT );

    damage( ch, victim, magic_damage( level, 11 ), sn, WEAR_NONE );
    return;
}


void spell_earthquake( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;

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

    for( vch = char_list; vch; vch = vch->next )
    {
	if( vch->deleted || !vch->in_room )
	    continue;

	if( vch->in_room == ch->in_room )
	{
	    if( vch != ch && !is_safe( ch, vch )
		&& ( !IS_NPC( ch ) || !IS_NPC( vch ) ) )
		damage( ch, vch, magic_damage( level, 4 ),
			sn, WEAR_NONE );
	    continue;
	}

	if( vch->in_room->area == ch->in_room->area )
	    send_to_char( "The earth trembles and shivers.\n\r", vch );
    }

    return;
}


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

    if( is_affected( victim, sn ) || saves_spell( level, victim, ch, sn ) )
	return;

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_HITROLL;
    af.modifier = -2 - level / 10;
    vzero( af.bitvector );
    affect_to_char( victim, &af, NULL );

    af.location = APPLY_MAGIC_RESIST;
    af.modifier = -2 - level / 20;
    affect_to_char( victim, &af, NULL );

    af.location = APPLY_AC;
    af.modifier = level / 2;
    affect_to_char( victim, &af, NULL );

    act( "You ridicule $N about $S childhood.", ch, NULL, victim, TO_CHAR );
    send_to_char( "Your ego takes a beating.\n\r", victim );
    act( "$N's ego is crushed by $n!", ch, NULL, victim, TO_NOTVICT );

    return;
}


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

    if( saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "Nothing seems to happen.\n\r", ch );
	return;
    }

    ch->alignment = UMAX( -1000, ch->alignment - 200 );
    if( victim->level <= 2 )
    {
	dam = ch->hit + 1;
    }
    else
    {
	gain_exp( victim, 0 - number_range( level / 2, 3 * level / 2 ) );
	for( dam = 0; dam < MAGIC_MAX; ++dam )
	    victim->mana[dam] /= 2;
	victim->move /= 2;
	dam = dice( 1, level );
	ch->hit += dam;
    }

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


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

    if( IS_AFFECTED( victim, AFF_FAERIE_FIRE ) )
	return;

    effect = UMIN( 2 * level, 500 );
    if( saves_spell( level, victim, ch, sn ) )
	effect /= 2;

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_AC;
    af.modifier = effect;
    vset( af.bitvector, AFF_FAERIE_FIRE );

    if( !affect_to_char( victim, &af, NULL ) )
	return;

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


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

    if( IS_AFFECTED( victim, AFF_BLEEDING )
	|| saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "They are allready afraid of their own shadow.", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = UMAX( 25, level / 8 + 3 );
    af.location = APPLY_HITROLL;
    af.modifier = UMIN( -10, -2 - ( level / 20 ) );
    vzero( af.bitvector );
    affect_to_char( victim, &af, NULL );

    af.modifier *= -1;
    af.location = APPLY_MAGIC_RESIST;
    affect_to_char( victim, &af, NULL );

    act( "$n show$% $N $S darkest fears.", ch, NULL, victim, TO_ALL );
    return;
}


void spell_fire_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj_lose;
    OBJ_DATA *obj_next;
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam;
    int hpch;

    if( number_percent( ) < level && !saves_spell( level, victim, ch, sn ) )
    {
	for( obj_lose = victim->carrying; obj_lose; obj_lose = obj_next )
	{
	    const char *msg;

	    obj_next = obj_lose->next_content;
	    if( obj_lose->deleted )
		continue;
	    if( number_bits( 3 ) != 0 )
		continue;

	    switch( obj_lose->item_type )
	    {
	    default:
		continue;
	    case ITEM_CONTAINER:
		msg = "$p ignites and burns!";
		break;
	    case ITEM_POTION:
		msg = "$p bubbles and boils!";
		break;
	    case ITEM_SCROLL:
		msg = "$p crackles and burns!";
		break;
	    case ITEM_STAFF:
		msg = "$p smokes and chars!";
		break;
	    case ITEM_WAND:
		msg = "$p sparks and sputters!";
		break;
	    case ITEM_FOOD:
	    case ITEM_LIMB:
		msg = "$p blackens and crisps!";
		break;
	    case ITEM_PILL:
		msg = "$p melts and drips!";
		break;
	    case ITEM_PLANT:
	    case ITEM_FURNITURE:
		msg = "$p crackles and burns!";
		break;
	    }

	    act( msg, victim, obj_lose, NULL, TO_CHAR );
	    mod_item_condition( victim, obj_lose, number_fuzzy( 1 ) );
	}
    }

    hpch = UMAX( 10, ch->hit );
    dam = number_range( hpch / 8 + 1, hpch / 4 );
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


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

    act( "&rYou direct a raging fire power to turn $N into a pillar of fire!",
	 ch, NULL, victim, TO_CHAR );
    act( "&rYou feel incredibile heat as $n uses $s fire power to incinerate you.",
	 ch, NULL, victim, TO_VICT );
    act( "&r$n summons a raging fire power to turn $N into a pillar of fire!",
	 ch, NULL, victim, TO_NOTVICT );

    damage( ch, victim, magic_damage( level, 11 ), sn, WEAR_NONE );
    return;
}


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

    if( !saves_spell( level, victim, ch, sn ) )
    {
	af.type = ( sn == gsn_weapon_spell )
	    ? skill_lookup( "freeze" ) : sn;
	af.duration = 6;
	af.location = APPLY_STR;
	af.modifier = -1;
	vzero( af.bitvector );
	affect_join( victim, &af );
    }

    damage( ch, victim, magic_damage( level, 3 ), sn, WEAR_NONE );
    return;
}


void spell_frost_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj_lose;
    OBJ_DATA *obj_next;
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam;
    int hpch;

    if( number_percent( ) < level && !saves_spell( level, victim, ch, sn ) )
    {
	for( obj_lose = victim->carrying; obj_lose; obj_lose = obj_next )
	{
	    obj_next = obj_lose->next_content;
	    if( obj_lose->deleted )
		continue;
	    if( number_bits( 3 ) != 0 )
		continue;

	    if( obj_lose->item_type != ITEM_CONTAINER
		&& obj_lose->item_type != ITEM_DRINK_CON
		&& obj_lose->item_type != ITEM_POTION )
		continue;

	    act( "$p freezes and shatters!", victim, obj_lose, NULL, TO_CHAR );
	    mod_item_condition( victim, obj_lose, number_fuzzy( 1 ) );
	}
    }

    hpch = UMAX( 10, ch->hit );
    dam = number_range( hpch / 8 + 1, hpch / 4 );

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


void spell_gale( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    EXIT_DATA *pexit;
    char buf[MAX_INPUT_LENGTH];
    int dam, door, dist;

    target_name = one_argument( target_name, buf );
    switch( *target_name )
    {
    case 'n':    case 'N':
	door = DIR_NORTH;
	break;
    case 'e':    case 'E':
	door = DIR_EAST;
	break;
    case 's':    case 'S':
	door = DIR_SOUTH;
	break;
    case 'w':    case 'W':
	door = DIR_WEST;
	break;
    case 'u':    case 'U':
	door = DIR_UP;
	break;
    case 'd':    case 'D':
	door = DIR_DOWN;
	break;
    default:
	door = -1;
	break;
    }

    if( door >= 0 )
	pexit = victim->in_room->exit[door];
    else
	pexit = NULL;

    dam = dice( level, 3 );
    act( "$n project$% a strong wind onto $N.", ch, NULL, victim, TO_ALL );
    if( saves_spell( level - get_size( victim ) / 8, victim, ch, sn ) )
    {
	act( "$n stands firm.", victim, NULL, NULL, TO_ROOM );
	damage( ch, victim, dam, sn, WEAR_NONE );
	return;
    }
    if( !pexit || IS_SET( pexit->exit_info, EX_CLOSED ) )
    {
	if( ( !IS_AFFECTED( victim, AFF_PASS_DOOR )
	      && !IS_SET( race_table[victim->race].race_abilities,
			  RACE_PASSDOOR ) )
	    || IS_SET( pexit->exit_info, EX_PASSPROOF ) )
	{
	    act( "$n is slammed violently into a wall.",
		 victim, NULL, NULL, TO_ROOM );
	    send_to_char( "You are crushed into a wall by the rush of air!\n\r",
			  victim );
	    dam *= UMIN( level / 30 + 1, 5 );
	    dam += dam * get_size( victim ) / 120;
	    damage( ch, victim, dam, sn, WEAR_NONE );
	    if( number_bits( 2 ) == 0 )
		victim->position = POS_SMASHED;
	    else
		victim->position = POS_GETTING_UP;
	    WAIT_STATE( victim, PULSE_VIOLENCE * 2 );
	    return;
	}
    }

    /*
     * Real gale movement.
     */
    damage( ch, victim, dam, sn, WEAR_NONE );
    if( ch->fighting != victim || victim->in_room != ch->in_room )
	return;
    stop_fighting( victim, TRUE );
    dam = dice( level, 3 );
    for( dist = number_fuzzy( level / 30 + 1 ); pexit && dist > 0; dist-- )
    {
	act( "&rYou are blown $t!", victim,
	     dir_name[door], NULL, TO_CHAR );
	act( "&r$n is thrown $t!", victim, dir_name[door], NULL, TO_ROOM );
	char_from_room( victim );
	char_to_room( victim, pexit->to_room );
	act( "$n is blown in from the $t.", victim,
	     dir_name[rev_dir[door]], NULL, TO_ROOM );
	pexit = victim->in_room->exit[door];
	if( pexit && IS_SET( pexit->exit_info, EX_CLOSED )
	    && ( ( !IS_AFFECTED( ch, AFF_PASS_DOOR )
		   && !IS_SET( race_table[ch->race].race_abilities,
			       RACE_PASSDOOR ) )
		 || IS_SET( pexit->exit_info, EX_PASSPROOF ) ) )
	    pexit = NULL;
    }
    if( dist > 0 )
    {
	dam *= UMIN( dist, 5 );
	dam += dam * get_size( victim ) / 120;
	act( "$n is slammed violently into a wall.",
	     victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are crushed into a wall by the rush of air!\n\r",
		      victim );
	if( number_bits( 2 ) == 0 )
	    victim->position = POS_SMASHED;
	else
	    victim->position = POS_GETTING_UP;
	damage( victim, victim, dam, sn, WEAR_NONE );
    }
    else
	victim->position = POS_GETTING_UP;
    WAIT_STATE( victim, PULSE_VIOLENCE * 2 );
    return;
}


void spell_gas_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    int dam;
    int hpch;

    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	hpch = UMAX( 10, ch->hit );
	dam = number_range( hpch / 8 + 1, hpch / 4 );
	damage( ch, vch, dam, sn, WEAR_NONE );
	if( !vch->deleted && vch->in_room == ch->in_room )
	    spell_poison( gsn_poison, level, ch, vch );
    }

    return;
}


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

    if( IS_NPC( ch ) )
	return;
    if( victim == ch )
    {
	send_to_char( "Not on yourself.\n\r", ch );
	return;
    }

    if( victim->fighting != ch )
    {
	victim->fighting = ch;
	if( victim->position != POS_SMASHED )
	    victim->position = POS_FIGHTING;
    }
    ch->fighting = victim;

    SET_BIT( ch->pcdata->pc_bits, PC_BIT_STRANGLE );
    SET_BIT( ch->pcdata->pc_bits, PC_BIT_HANDOFKAZ );
    send_to_char( "You reach into their chest and grasp their heart.\n\r", ch );
    act( "$n suddenly reaches into your chest and begins to squeeze your heart!",
	 ch, NULL, victim, TO_VICT );
    act( "$n reaches through $N's chest to sieze $S heart!",
	 ch, NULL, victim, TO_NOTVICT );
    if( get_time_left( ch->in_room->events, evn_room_violence ) < 0 )
	create_room_event( ch->in_room, evn_room_violence,
			   PULSE_VIOLENCE );
    return;
}


void spell_hellfire( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;

    act( "$n summon$% the fires of hell and set$% the room ablaze!",
	ch, NULL, NULL, TO_ALL );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	damage( ch, vch, magic_damage( level, 7 ), sn, WEAR_NONE );
    }
    return;
}


void spell_holylight( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    int dam, heal, score, top, bottom;

    act( "You call the power of $g.",
	 ch, NULL, NULL, TO_CHAR );
    act( "$n calls forth a beam of heavenly light!",
	 ch, NULL, NULL, TO_ROOM );

    if( ch->alignment > 750 )
    {
	top = 1000;
	bottom = 500;
    }
    else if( ch->alignment < -750 )
    {
	bottom = -1000;
	top = -500;
    }
    else
    {
	top = ch->alignment + 250;
	bottom = ch->alignment - 250;
    }

    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->alignment < ch->alignment )
	    score = ( vch->alignment - bottom ) * 1000
		/ ( ch->alignment - bottom );
	else if( vch->alignment > ch->alignment )
	    score = ( top - vch->alignment ) * 1000
		/ ( top - ch->alignment );
	else
	    score = 1000;
	if( is_same_group( ch, vch ) && score > 20 )
	{
	    heal = level + get_curr_wis( ch ) / 10 + number_range( 1, 3 );
	    heal = heal * score / 1000;
	    heal = UMAX( 1, heal );
	    if( vch->hit < vch->max_hit )
		vch->hit = UMIN( vch->hit + heal, vch->max_hit );
	    else
		vch->hit = UMAX( vch->hit - heal, vch->max_hit );
	    update_pos( vch );
	    act( "$n looks better.", vch, NULL, NULL, TO_ROOM );
	    send_to_char( "You feel better!\n\r", vch );
	    continue;
	}
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) )
	    || score < -100 )
	    continue;
	dam = number_range( vch->hit / 20, vch->hit / 16 );
	dam = dam * score / -3000;
	damage( ch, vch, dam, sn, WEAR_NONE );
    }
    return;
}


void spell_inferno( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;

    send_to_room( "Sheets of flame rage around the room!", ch->in_room );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch )	) )
	    continue;
	damage( ch, vch, magic_damage( level, 5 ), sn, WEAR_NONE );
    }
    return;
}


void spell_lightning_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam;
    int hpch;

    hpch = UMAX( 10, ch->hit );
    dam = number_range( hpch / 8 + 1, hpch / 4 );
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


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

    if( IS_AFFECTED( victim, AFF_SLEEP )
	|| level < number_fuzzy( victim->level ) - 3
	|| saves_spell( level + 5, victim, ch, sn )
	|| !str_cmp( race_table[victim->race].name, "Vampire" ) )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }

    af.type = gsn_sleep;
    af.level = level;
    af.duration = 4 + level;
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_SLEEP );
    affect_to_char( victim, &af, ch );

    act( "$N sings $n a lullaby and he falls asleep.", victim, NULL, ch, TO_ROOM );
    if( IS_AWAKE( victim ) )
    {
	send_to_char( "You feel very sleepy ..... zzzzzz.\n\r", victim );
	if( victim->position == POS_FIGHTING )
	    stop_fighting( victim, TRUE );
	do_sleep( victim, "" );
    }
    return;
}


void spell_mass_plague( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    AFFECT_DATA af;

    af.type = gsn_plague;
    af.level = level;
    af.location = APPLY_STR;
    af.modifier = -2 - level / 20;
    af.duration = 20 + level / 10;
    vset( af.bitvector, AFF_PLAGUE );
    for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
    {
	if( vch->deleted || IS_AFFECTED( vch, AFF_PLAGUE ) )
	    continue;
	if( saves_spell( level, vch, ch, sn ) )
	    continue;
	act( "Angry red sores erupt from $n's skin.",
	     vch, NULL, NULL, TO_ROOM );
	send_to_char( "You feel very sick.\n\r", vch );
	affect_to_char( vch, &af, NULL );
    }
    return;
}


void spell_meteor_swarm( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    int dam;

    act( "$n calls a rain of stones from the heavens!",
	ch, NULL, NULL, TO_ROOM );
    act( "You call stones from the heavens to strike your enemies!",
	ch, NULL, NULL, TO_CHAR );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	dam = magic_damage( level, 8 );
	dam = dam * ( get_size( vch ) / 3 + 20 ) / 80;
	damage( ch, vch, dam, sn, WEAR_NONE );
    }
    return;
}


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

    /* This is an EXTREMELY crippling spell, make it hard to put on */
    if( IS_AFFECTED( victim, AFF_MIND_MIST )
	|| saves_spell( level, victim, ch, sn )
	|| number_bits( 2 ) == 0 )
	return;

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_EXP;
    af.modifier = -5 * level;
    vset( af.bitvector, AFF_MIND_MIST );
    affect_to_char( victim, &af, NULL );

    act( "You magically block $N from $S memories and $E forgets.",
	 ch, NULL, victim, TO_CHAR );
    act( "$n has forced you to forget... but you forget what.",
	 ch, NULL, victim, TO_VICT );
    act( "$n blocks $N's memories, making $M forget.",
	 ch, NULL, victim, TO_NOTVICT );

    return;
}


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

    if( IS_AFFECTED( victim, AFF_MUTE )
	|| saves_spell( level, victim, ch, sn ) )
	return;

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = 0;
    af.modifier = 0;
    vset( af.bitvector, AFF_MUTE );
    affect_to_char( victim, &af, NULL );

    act( "You have silenced $N!", ch, NULL, victim, TO_CHAR );
    act( "$n has silenced $N!", ch, NULL, victim, TO_ROOM );
    return;
}


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

    if( IS_AFFECTED( victim, AFF_PLAGUE )
	|| IS_SET( race_table[victim->race].race_abilities, RACE_UNDEAD )
	|| saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = level;
    af.location = APPLY_STR;
    af.modifier = -2 - level / 20;
    vset( af.bitvector, AFF_PLAGUE );
    affect_to_char( victim, &af, NULL );

    act( "Sores break out all over $n's body.", victim, NULL, NULL, TO_ROOM );
    send_to_char( "You feel very sick.\n\r", victim );
    return;
}


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

    dam = magic_damage( level, 5 );

    if( !saves_spell( level, victim, ch, sn )
	&& !IS_SET( race_table[ch->race].race_abilities, RACE_NO_POISON ) )
    {
	af.type = sn;
	af.duration = level;
	af.location = APPLY_STR;
	af.modifier = -2 - level / 20;
	vset( af.bitvector, AFF_POISON );
	affect_join( victim, &af );
	send_to_char( "You feel very sick.\n\r", victim );
    }
    else
	dam /= 2;
    damage( ch, victim, dam, sn, WEAR_NONE );
    return;
}


/*
 * The following spells are pure damage spells.
 * Most plain damage spells use one of these.
 */
void spell_power_2( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 2 ), sn, WEAR_NONE );
    return;
}


void spell_power_3( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 3 ), sn, WEAR_NONE );
    return;
}


void spell_power_4( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 4 ), sn, WEAR_NONE );
    return;
}


void spell_power_5( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 5 ), sn, WEAR_NONE );
    return;
}


void spell_power_6( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 6 ), sn, WEAR_NONE );
    return;
}


void spell_power_8( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 8 ), sn, WEAR_NONE );
    return;
}


void spell_power_9( int sn, int level, CHAR_DATA *ch, void *vo )
{
    damage( ch, (CHAR_DATA *)vo, magic_damage( level, 9 ), sn, WEAR_NONE );
    return;
}


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

    dam = magic_damage( level, 9 );
    dam += ( 20 + get_curr_int( ch ) ) * level / 25;
    damage( ch, victim, dam, sn, WEAR_NONE );
}


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

    if( is_affected( victim, sn ) || saves_spell( level, victim, ch, sn ) )
	return;

    af.type = sn;
    af.level = level;
    af.duration = level / 2;
    af.location = APPLY_STR;
    af.modifier = -1 - ( level >= 15 ) - ( level >= 30 ) - ( level >= 50 );
    vzero( af.bitvector );
    affect_to_char( victim, &af, NULL );

    send_to_char( "You feel drained.\n\r", victim );
    act( "$n appears drained of strength.", victim, NULL, NULL, TO_ROOM );
    return;
}


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

    if( IS_AFFECTED( victim, AFF_SLEEP )
	|| level < victim->level
	|| saves_spell( level, victim, ch, sn )
	|| !str_cmp( race_table[victim->race].name, "Vampire" ) )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }

    af.type = sn;
    af.duration = 4 + level;
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_SLEEP );
    affect_join( victim, &af );

    if( IS_AWAKE( victim ) )
    {
	send_to_char( "You feel very sleepy ..... zzzzzz.\n\r", victim );
	if( victim->position == POS_FIGHTING )
	    stop_fighting( victim, TRUE );
	do_sleep( victim, "" );
    }
    return;
}


void spell_soul_blast( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    int dam, i;

    dam = ch->hit * 3 / 2;
    ch->hit = 1;
    for( i = 0; i < MAGIC_MAX; ++i )
    {
	dam += ch->mana[i] - 1;
	ch->mana[i] = 1;
    }
    dam += ch->move / 2;
    ch->move = 1;
    ch->position = POS_SMASHED;

    damage( ch, victim, dam, sn, WEAR_NONE );
}


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

    act( "&wYour subtle spirit power attacks $N's life force!",
	 ch, NULL, victim, TO_CHAR );
    act( "&wYou suddenly feel a wave of intense pain from $o spirit power!",
	 ch, NULL, victim, TO_VICT );
    act( "&w$n gestures and $N screams in agony as his spirit is flayed!",
	 ch, NULL, victim, TO_NOTVICT );

    damage( ch, victim, magic_damage( level, 11 ), sn, WEAR_NONE );
    return;
}


void spell_ultrablast( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    int dam;
    int hpch;

    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	hpch = UMAX( 10, ch->hit );
	dam = number_range( hpch / 8 + 1, hpch / 4 );
	damage( ch, vch, dam, sn, WEAR_NONE );
    }
    return;
}


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

    if( victim->level >= level
	|| saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "You have failed.\n\r", ch );
	return;
    }

    if( IS_SET( race_table[victim->race].race_abilities, RACE_UNDEAD ) )
	do_flee( victim, "" );

    return;
}


void spell_vampiric_bite( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *)vo;
    OBJ_DATA *obj;
    AFFECT_DATA af;
    int dam;

    dam = dice( 5, level );
    damage( ch, victim, dam, sn, WEAR_NONE );
    ch->hit = UMIN( ch->max_hit, ch->hit + dam );

    if( victim->level < 11 || get_age( victim ) < 21 )
	return;

    if( IS_AFFECTED( victim, AFF_POLYMORPH ) )
	return;

    if( saves_spell( level, victim, ch, sn )
	|| number_bits( 1 ) == 0 )
	return;

    if( ( obj = get_eq_char( victim, WEAR_HOLD_L ) ) )
    {
	if( IS_OBJ_STAT( obj, ITEM_VAMPIRE_BANE )
	    && ch->level < 21 )
	    return;
	else
	{
	    if( IS_OBJ_STAT( obj, ITEM_HOLY ) )
	    {
		if( ch->level < 32 )
		{
		    return;
		}
		else
		{
		    if( victim->level > ch->level )
			return;
		}
	    }
	}
    }

    af.type = sn;
    af.duration = UMAX( 5, 30 - level );
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_VAMP_BITE );
    affect_join( victim, &af );

    if( ch != victim )
	send_to_char( "Ahh!  Taste the power!\n\r", ch );
    send_to_char( "Your blood begins to burn!\n\r", victim );
    return;
}


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

    if( is_affected( victim, sn ) || saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = level / 5;
    af.location = APPLY_CON;
    af.modifier = -2;
    vset( af.bitvector, AFF_WARP_FLESH );
    affect_to_char( victim, &af, NULL );

    act( "$n's flesh &gsickens&n and turns horribly!", victim, NULL, NULL, TO_ROOM );
    send_to_char( "You feel sick.\n\r", victim );
    return;
}


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

    act( "&b$N begins to dissolve under the onslaught of your water power!",
	 ch, NULL, victim, TO_CHAR );
    act( "&bYou feel your entire body dissolving from $o water power!",
	 ch, NULL, victim, TO_VICT );
    act( "&b$O form begins to dissolve as $o water power attacks!",
	 ch, NULL, victim, TO_NOTVICT );

    damage( ch, victim, magic_damage( level, 11 ), sn, WEAR_NONE );
    return;
}


void spell_wave_of_oblivion( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;

    act( "$n pounds the room with a wave of &Kdarkness&x!",
	 ch, NULL, NULL, TO_ROOM );
    act( "You pound your enemies with a wave of &Kdarkness&x!",
	 ch, NULL, NULL, TO_CHAR );
    for( vch = ch->in_room->people; vch; vch = vch_next )
    {
	vch_next = vch->next_in_room;
	if( vch->deleted || ch == vch || is_safe( ch, vch )
	    || ( IS_NPC( ch ) && IS_NPC( vch ) ) )
	    continue;
	damage( ch, vch, magic_damage( level, 7 ), sn, WEAR_NONE );
    }
    return;
}


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

    if( is_affected( victim, sn ) || saves_spell( level, victim, ch, sn ) )
    {
	send_to_char( "They shrug off your attack.\n\r", ch );
	return;
    }

    af.type = sn;
    af.level = level;
    af.duration = level / 2;
    af.location = APPLY_STR;
    af.modifier = -2;
    vzero( af.bitvector );
    affect_to_char( victim, &af, NULL );

    if( ch != victim )
	send_to_char( "Ok.\n\r", ch );
    send_to_char( "You feel weaker.\n\r", victim );
    return;
}


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

    if( sn != gsn_web )
	act( "$n gesture$% and a weeds spring from the ground, grabbing at $N.",
	     ch, NULL, victim, TO_ALL );
    if( is_affected( victim, sn ) || saves_spell( level, victim, ch, sn ) )
    {
	if( sn == gsn_web )
	    act( "Webs shoot from $o fingers just missing $N.",
		 ch, NULL, victim, TO_ALL );
	else	/* tangleweed */
	    act( "The mass of writhing weeds fail to entangle $m.",
		 ch, NULL, victim, TO_ALL );
	return;
    }

    affect_strip( victim, gsn_web );

    af.type = gsn_web;
    af.level = level;
    af.duration = UMAX( 1 + ( level / 8 ), 24 );
    af.location = APPLY_STR;
    af.modifier = -5 - level / 50;
    vset( af.bitvector, AFF_HOLD );

    if( sn == gsn_web )
	act( "Webs shoot from $o fingers covering $N in sticky strands.",
	     ch, NULL, victim, TO_ALL );
    else
	act( "The weeds grab $N, quickly binding him hand and foot.",
	     ch, NULL, victim, TO_ALL );

    affect_to_char( victim, &af, NULL );
    return;
}