/*___________________________________________________________________________*
)()( 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;
}