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