/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* 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. *
***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
/*
* Local functions.
*/
void say_spell args( ( CHAR_DATA *ch, int sn ) );
/*
* Lookup a skill by name.
*/
int skill_lookup( const char *name )
{
int sn;
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( LOWER(name[0]) == LOWER(skill_table[sn].name[0])
&& !str_prefix( name, skill_table[sn].name ) )
return sn;
}
return -1;
}
/*
* Lookup a skill by slot number.
* Used for object loading.
*/
int slot_lookup( int slot )
{
extern bool fBootDb;
int sn;
if ( slot <= 0 )
return -1;
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( slot == skill_table[sn].slot )
return sn;
}
if ( fBootDb )
{
bug( "Slot_lookup: bad slot %d.", slot );
abort( );
}
return -1;
}
/*
* Utter mystical words for an sn.
*/
void say_spell( CHAR_DATA *ch, int sn )
{
char buf [MAX_STRING_LENGTH];
char buf2 [MAX_STRING_LENGTH];
CHAR_DATA *rch;
char *pName;
int iSyl;
int length;
struct syl_type
{
char * old;
char * new;
};
static const struct syl_type syl_table[] =
{
{ " ", " " },
{ "ar", "abra" },
{ "au", "kada" },
{ "bless", "fido" },
{ "blind", "nose" },
{ "bur", "mosa" },
{ "cu", "judi" },
{ "de", "oculo" },
{ "en", "unso" },
{ "light", "dies" },
{ "lo", "hi" },
{ "mor", "zak" },
{ "move", "sido" },
{ "ness", "lacri" },
{ "ning", "illa" },
{ "per", "duda" },
{ "ra", "gru" },
{ "re", "candus" },
{ "son", "sabru" },
{ "tect", "infra" },
{ "tri", "cula" },
{ "ven", "nofo" },
{ "a", "a" }, { "b", "b" }, { "c", "q" }, { "d", "e" },
{ "e", "z" }, { "f", "y" }, { "g", "o" }, { "h", "p" },
{ "i", "u" }, { "j", "y" }, { "k", "t" }, { "l", "r" },
{ "m", "w" }, { "n", "i" }, { "o", "a" }, { "p", "s" },
{ "q", "d" }, { "r", "f" }, { "s", "g" }, { "t", "h" },
{ "u", "j" }, { "v", "z" }, { "w", "x" }, { "x", "n" },
{ "y", "l" }, { "z", "k" },
{ "", "" }
};
buf[0] = '\0';
for ( pName = skill_table[sn].name; *pName != '\0'; pName += length )
{
for ( iSyl = 0; (length = strlen(syl_table[iSyl].old)) != 0; iSyl++ )
{
if ( !str_prefix( syl_table[iSyl].old, pName ) )
{
strcat( buf, syl_table[iSyl].new );
break;
}
}
if ( length == 0 )
length = 1;
}
sprintf( buf2, "$n utters the words, '%s'.", buf );
sprintf( buf, "$n utters the words, '%s'.", skill_table[sn].name );
for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
{
if ( rch != ch )
act( ch->class==rch->class ? buf : buf2, ch, NULL, rch, TO_VICT );
}
return;
}
/*
* Compute a saving throw.
* Negative apply's make saving throw better.
*/
bool saves_spell( int level, CHAR_DATA *victim )
{
return FALSE; /* TODO */
}
/*
* The kludgy global is for spells who want more stuff from command line.
*/
char *target_name;
void do_cast( CHAR_DATA *ch, char *argument )
{
/* TODO */
return;
}
/*
* Cast spells at targets using a magical object.
*/
void obj_cast_spell( int sn, int level, CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
void *vo;
if ( sn <= 0 )
return;
if ( sn >= MAX_SKILL || skill_table[sn].spell_fun == 0 )
{
bug( "Obj_cast_spell: bad sn %d.", sn );
return;
}
switch ( skill_table[sn].target )
{
default:
bug( "Obj_cast_spell: bad target for sn %d.", sn );
return;
case TAR_IGNORE:
vo = NULL;
break;
case TAR_CHAR_OFFENSIVE:
if ( victim == NULL )
victim = ch->fighting;
if ( victim == NULL || !IS_NPC(victim) )
{
send_to_char( "You can't do that.\n\r", ch );
return;
}
vo = (void *) victim;
break;
case TAR_CHAR_DEFENSIVE:
if ( victim == NULL )
victim = ch;
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
vo = (void *) ch;
break;
case TAR_OBJ_INV:
if ( obj == NULL )
{
send_to_char( "You can't do that.\n\r", ch );
return;
}
vo = (void *) obj;
break;
}
target_name = "";
(*skill_table[sn].spell_fun) ( sn, level, ch, vo );
if ( skill_table[sn].target == TAR_CHAR_OFFENSIVE && victim->master != ch )
{
CHAR_DATA *vch;
CHAR_DATA *vch_next;
for ( vch = ch->in_room->people; vch; vch = vch_next )
{
vch_next = vch->next_in_room;
if ( victim == vch && victim->fighting == NULL )
{
multi_hit( victim, ch, TYPE_UNDEFINED );
break;
}
}
}
return;
}
/*
* Spell functions.
*/
void spell_acid_blast( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
/* TODO */
dam = dice( 30, 6 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_armor( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = 24;
af.modifier = -20;
af.location = APPLY_AC;
af.bitvector = 0;
affect_to_char( victim, &af );
send_to_char( "You feel someone protecting you.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_bless( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( victim->position == POS_FIGHTING || is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = 50;
af.location = APPLY_HITROLL;
af.modifier = 5;
af.bitvector = 0;
affect_to_char( victim, &af );
af.location = APPLY_SAVING_SPELL;
af.modifier = 0 - 5;
affect_to_char( victim, &af );
send_to_char( "You feel righteous.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
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 ) )
return;
af.type = sn;
af.location = APPLY_HITROLL;
af.modifier = -4;
af.duration = 30;
af.bitvector = AFF_BLIND;
affect_to_char( victim, &af );
send_to_char( "You are blinded!\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_burning_hands( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
0, 0, 0, 0, 14, 17, 20, 23, 26, 29,
29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
44, 44, 45, 45, 46, 46, 47, 47, 48, 48
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_call_lightning( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
CHAR_DATA *vch_next;
int dam;
if ( !IS_OUTSIDE(ch) )
{
send_to_char( "You must be out of doors.\n\r", ch );
return;
}
if ( weather_info.sky < SKY_RAINING )
{
send_to_char( "You need bad weather.\n\r", ch );
return;
}
dam = dice(level/2, 8);
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 != NULL; vch = vch_next )
{
vch_next = vch->next;
if ( vch->in_room == NULL )
continue;
if ( vch->in_room == ch->in_room )
{
if ( vch != ch && ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) ) )
damage( ch, vch, saves_spell( level, vch ) ? dam/2 : dam, sn );
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_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
damage( ch, (CHAR_DATA *) vo, dice(1, 8) + level / 3, sn );
return;
}
void spell_cause_critical( int sn, int level, CHAR_DATA *ch, void *vo )
{
damage( ch, (CHAR_DATA *) vo, dice(3, 8) + level - 6, sn );
return;
}
void spell_cause_serious( int sn, int level, CHAR_DATA *ch, void *vo )
{
damage( ch, (CHAR_DATA *) vo, dice(2, 8) + level / 2, sn );
return;
}
void spell_change_sex( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = 10 * level;
af.location = APPLY_SEX;
do
{
af.modifier = number_range( 0, 2 ) - victim->sex;
}
while ( af.modifier == 0 );
af.bitvector = 0;
affect_to_char( victim, &af );
send_to_char( "You feel different.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
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 ( IS_AFFECTED(victim, AFF_CHARM)
|| IS_AFFECTED(ch, AFF_CHARM)
|| saves_spell( level, victim ) )
return;
if ( victim->master )
stop_follower( victim );
add_follower( victim, ch );
af.type = sn;
af.duration = number_fuzzy( level / 4 );
af.location = 0;
af.modifier = 0;
af.bitvector = AFF_CHARM;
affect_to_char( victim, &af );
act( "Isn't $n just so nice?", ch, NULL, victim, TO_VICT );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_chill_touch( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
0, 0, 6, 7, 8, 9, 12, 13, 13, 13,
14, 14, 14, 15, 15, 15, 16, 16, 16, 17,
17, 17, 18, 18, 18, 19, 19, 19, 20, 20,
20, 21, 21, 21, 22, 22, 22, 23, 23, 23,
24, 24, 24, 25, 25, 25, 26, 26, 26, 27
};
AFFECT_DATA af;
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( !saves_spell( level, victim ) )
{
af.type = sn;
af.duration = 6;
af.location = APPLY_STR;
af.modifier = -1;
af.bitvector = 0;
affect_join( victim, &af );
}
else
{
dam /= 2;
}
damage( ch, victim, dam, sn );
return;
}
void spell_colour_spray( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30, 35, 40, 45, 50, 55, 55, 55, 56, 57,
58, 58, 59, 60, 61, 61, 62, 63, 64, 64,
65, 66, 67, 67, 68, 69, 70, 70, 71, 72,
73, 73, 74, 75, 76, 76, 77, 78, 79, 79
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_continual_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *light;
light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ) );
obj_to_room( light, ch->in_room );
act( "$n twiddles $s thumbs and $p appears.", ch, light, NULL, TO_ROOM );
act( "You twiddle your thumbs and $p appears.", ch, light, NULL, TO_CHAR );
return;
}
void spell_control_weather( int sn, int level, CHAR_DATA *ch, void *vo )
{
if ( !str_cmp( target_name, "better" ) )
weather_info.change += dice( level / 3, 4 );
else if ( !str_cmp( target_name, "worse" ) )
weather_info.change -= dice( level / 3, 4 );
else
send_to_char ("Do you want it to get better or worse?\n\r", ch );
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_create_food( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *mushroom;
mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ) );
mushroom->food->bite = 5 + level;
obj_to_room( mushroom, ch->in_room );
act( "$p suddenly appears.", ch, mushroom, NULL, TO_ROOM );
act( "$p suddenly appears.", ch, mushroom, NULL, TO_CHAR );
return;
}
void spell_create_spring( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *spring;
spring = create_object( get_obj_index( OBJ_VNUM_SPRING ) );
spring->timer = level;
obj_to_room( spring, ch->in_room );
act( "$p flows from the ground.", ch, spring, NULL, TO_ROOM );
act( "$p flows from the ground.", ch, spring, NULL, TO_CHAR );
return;
}
void spell_create_water( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
int water;
if( obj->item_type != ITEM_DRINK_CON )
{
send_to_char( "It is unable to hold water.\n\r", ch );
return;
}
if( obj->drink->liquid != LIQ_WATER && obj->drink->volume != 0 )
{
send_to_char( "It contains some other liquid.\n\r", ch );
return;
}
water = UMIN( level * ( weather_info.sky >= SKY_RAINING ? 4 : 2 ),
obj->drink->limit - obj->drink->volume );
if( water > 0 )
{
obj->drink->liquid = LIQ_WATER;
obj->drink->volume += water;
if( !is_name( "water", obj->name ) )
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "%s water", obj->name );
free_string( obj->name );
obj->name = str_dup( buf );
}
act( "$p is filled.", ch, obj, NULL, TO_CHAR );
}
return;
}
void spell_cure_blindness( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
if ( !is_affected( victim, gsn_blindness ) )
return;
affect_strip( victim, gsn_blindness );
send_to_char( "Your vision returns!\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_cure_critical( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int heal;
heal = dice(3, 8) + level - 6;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
send_to_char( "You feel better!\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_cure_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int heal;
heal = dice(1, 8) + level / 3;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
send_to_char( "You feel better!\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_cure_poison( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
if ( is_affected( victim, gsn_poison ) )
{
affect_strip( victim, gsn_poison );
act( "$N looks better.", ch, NULL, victim, TO_NOTVICT );
send_to_char( "A warm feeling runs through your body.\n\r", victim );
send_to_char( "Ok.\n\r", ch );
}
return;
}
void spell_cure_serious( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int heal;
heal = dice(2, 8) + level /2 ;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
send_to_char( "You feel better!\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_curse( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_CURSE) || saves_spell( level, victim ) )
return;
af.type = sn;
af.duration = 4*level;
af.location = APPLY_HITROLL;
af.modifier = -1;
af.bitvector = AFF_CURSE;
affect_to_char( victim, &af );
af.location = APPLY_SAVING_SPELL;
af.modifier = 1;
affect_to_char( victim, &af );
send_to_char( "You feel unclean.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_detect_evil( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_DETECT_EVIL) )
return;
af.type = sn;
af.duration = level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bitvector = AFF_DETECT_EVIL;
affect_to_char( victim, &af );
send_to_char( "Your eyes tingle.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_detect_hidden( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_DETECT_HIDDEN) )
return;
af.type = sn;
af.duration = level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_DETECT_HIDDEN;
affect_to_char( victim, &af );
send_to_char( "Your awareness improves.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_detect_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_DETECT_INVIS) )
return;
af.type = sn;
af.duration = level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bitvector = AFF_DETECT_INVIS;
affect_to_char( victim, &af );
send_to_char( "Your eyes tingle.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_detect_magic( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_DETECT_MAGIC) )
return;
af.type = sn;
af.duration = level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bitvector = AFF_DETECT_MAGIC;
affect_to_char( victim, &af );
send_to_char( "Your eyes tingle.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_detect_poison( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
if( IS_SET( obj->item_type, ITEM_FOOD ) )
{
if( obj->food->poison != 0 )
send_to_char( "You smell poisonous fumes.\n\r", ch );
else
send_to_char( "It looks very delicious.\n\r", ch );
}
else if( IS_SET( obj->item_type, ITEM_DRINK_CON ) )
{
if( obj->drink->poison != 0 )
send_to_char( "You smell poisonous fumes.\n\r", ch );
else
send_to_char( "It looks very delicious.\n\r", ch );
}
else
{
send_to_char( "It doesn't look poisoned.\n\r", ch );
}
return;
}
void spell_dispel_magic( int sn, int level, CHAR_DATA *ch, void *vo )
{
struct dispel_NPC_info
{
int value;
char *room_msg;
};
int lcv;
const int NUM_SPELLS = 13;
const struct dispel_NPC_info affect_bit[]=
{
{ AFF_INVISIBLE, "$n slowly fades back into existance." },
{ AFF_DETECT_EVIL, "" },
{ AFF_DETECT_INVIS, "" },
{ AFF_DETECT_MAGIC, "" },
{ AFF_DETECT_HIDDEN, "" },
{ AFF_SANCTUARY, "The white glow around $n's body fades."},
{ AFF_FAERIE_FIRE, "The red glow around $n's body fades."},
{ AFF_INFRARED, "" },
{ AFF_PROTECT, "" },
{ AFF_CHARM, "" },
{ AFF_SLEEP, "" },
{ AFF_FLYING, "$n slowly falls back to earth." },
{ AFF_PASS_DOOR, "$n looks much more solid." }
};
CHAR_DATA *victim;
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
victim = (CHAR_DATA *) vo;
if( (saves_spell( level, victim )) && (!ch->wizbit) )
{
send_to_char( "Your spell was resisted!\n\r", ch );
return;
}
for ( paf = victim->affected; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if ( paf_next == NULL
|| paf_next->type != paf->type )
{
if ( paf->type > 0 && skill_table[paf->type].msg_off )
{
if( !IS_NPC(victim) )
{
send_to_char( skill_table[paf->type].msg_off, victim );
send_to_char( "\n\r", victim );
}
if (paf->type == 57) /*sanc*/
act("The white glow around $n's body fades.",victim, NULL,
victim, TO_NOTVICT);
else if (paf->type == 35) /*faerie fire*/
act("The red glow around $n's body fades.", victim, NULL,
victim, TO_NOTVICT);
else if (paf->type == 39) /*fly*/
act("$n slowly falls back to earth.", victim, NULL, victim,
TO_NOTVICT);
else if (paf->type == 46) /*invis*/
act("$n slowly fades back into existance.", victim, NULL,
victim, TO_NOTVICT);
else if (paf->type == 52) /*pass door*/
act("$n looks much more solid.", victim, NULL, victim,
TO_NOTVICT);
}
}
affect_remove( victim, paf );
}
/*
for loop for MOBs who have the affected bit while not having the actual
spell affected. (They were given the affect at creation, not as a spell).
*/
for ( lcv = 0; lcv < NUM_SPELLS; lcv++)
{
if (IS_SET(victim->affected_by, affect_bit[lcv].value))
{
REMOVE_BIT(victim->affected_by, affect_bit[lcv].value);
if (affect_bit[lcv].room_msg)
act(affect_bit[lcv].room_msg, victim, NULL, victim, TO_NOTVICT);
}
}
}
void spell_dispel_evil( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
if ( !IS_NPC(ch) && IS_EVIL(ch) )
victim = ch;
if ( IS_GOOD(victim) )
{
act( "God protects $N.", ch, NULL, victim, TO_ROOM );
return;
}
if ( IS_NEUTRAL(victim) )
{
act( "$N does not seem to be affected.", ch, NULL, victim, TO_CHAR );
return;
}
dam = dice( level, 4 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_earthquake( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
CHAR_DATA *vch_next;
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 != NULL; vch = vch_next )
{
vch_next = vch->next;
if ( vch->in_room == NULL )
continue;
if ( vch->in_room == ch->in_room )
{
if ( vch != ch && ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) ) )
damage( ch, vch, level + dice(2, 8), sn );
continue;
}
if ( vch->in_room->area == ch->in_room->area )
send_to_char( "The earth trembles and shivers.\n\r", vch );
}
return;
}
void spell_enchant_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA *paf;
if ( obj->item_type != ITEM_WEAPON
|| IS_OBJ_STAT(obj, ITEM_MAGIC)
|| obj->affected != NULL )
return;
if ( affect_free == NULL )
{
paf = alloc_perm( sizeof(*paf) );
}
else
{
paf = affect_free;
affect_free = affect_free->next;
}
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_HITROLL;
paf->modifier = level / 5;
paf->bitvector = 0;
paf->next = obj->affected;
obj->affected = paf;
if ( affect_free == NULL )
{
paf = alloc_perm( sizeof(*paf) );
}
else
{
paf = affect_free;
affect_free = affect_free->next;
}
paf->type = -1;
paf->duration = -1;
paf->location = APPLY_DAMROLL;
paf->modifier = level / 10;
paf->bitvector = 0;
paf->next = obj->affected;
obj->affected = paf;
if ( IS_GOOD(ch) )
{
SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
act( "$p glows blue.", ch, obj, NULL, TO_CHAR );
}
else if ( IS_EVIL(ch) )
{
SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
act( "$p glows red.", ch, obj, NULL, TO_CHAR );
}
else
{
SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
act( "$p glows yellow.", ch, obj, NULL, TO_CHAR );
}
send_to_char( "Ok.\n\r", ch );
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 ) )
return;
ch->alignment = UMAX(-1000, ch->alignment - 200);
victim->mana /= 2;
victim->move /= 2;
dam = dice(1, level);
ch->hit += dam;
damage( ch, victim, dam, sn );
return;
}
void spell_fireball( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 30, 35, 40, 45, 50, 55,
60, 65, 70, 75, 80, 82, 84, 86, 88, 90,
92, 94, 96, 98, 100, 102, 104, 106, 108, 110,
112, 114, 116, 118, 120, 122, 124, 126, 128, 130
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_flamestrike( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
dam = dice(6, level);
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_faerie_fire( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_FAERIE_FIRE) )
return;
af.type = sn;
af.duration = level;
af.location = APPLY_AC;
af.modifier = 2 * level;
af.bitvector = AFF_FAERIE_FIRE;
affect_to_char( victim, &af );
send_to_char( "You are surrounded by a pink outline.\n\r", victim );
act( "$n is surrounded by a pink outline.", victim, NULL, NULL, TO_ROOM );
return;
}
void spell_faerie_fog( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *ich;
act( "$n conjures a cloud of purple smoke.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You conjure a cloud of purple smoke.\n\r", ch );
for ( ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room )
{
if ( !IS_NPC(ich) && IS_SET(ich->act, PLR_WIZINVIS) )
continue;
if ( ich == ch || saves_spell( level, ich ) )
continue;
affect_strip ( ich, gsn_invis );
affect_strip ( ich, gsn_mass_invis );
affect_strip ( ich, gsn_sneak );
REMOVE_BIT ( ich->affected_by, AFF_HIDE );
REMOVE_BIT ( ich->affected_by, AFF_INVISIBLE );
REMOVE_BIT ( ich->affected_by, AFF_SNEAK );
act( "$n is revealed!", ich, NULL, NULL, TO_ROOM );
send_to_char( "You are revealed!\n\r", ich );
}
return;
}
void spell_fly( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_FLYING) )
return;
af.type = sn;
af.duration = level + 3;
af.location = 0;
af.modifier = 0;
af.bitvector = AFF_FLYING;
affect_to_char( victim, &af );
send_to_char( "Your feet rise off the ground.\n\r", victim );
act( "$n's feet rise off the ground.", victim, NULL, NULL, TO_ROOM );
return;
}
void spell_gate( int sn, int level, CHAR_DATA *ch, void *vo )
{
char_to_room( create_mobile( get_mob_index(MOB_VNUM_VAMPIRE) ),
ch->in_room );
return;
}
/*
* Spell for mega1.are from Glop/Erkenbrand.
*/
void spell_general_purpose( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
dam = number_range( 25, 100 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_giant_strength( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = level;
af.location = APPLY_STR;
af.modifier = 1 + (level >= 18) + (level >= 25);
af.bitvector = 0;
affect_to_char( victim, &af );
send_to_char( "You feel stronger.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_harm( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
dam = UMAX( 20, victim->hit - dice(1,4) );
if ( saves_spell( level, victim ) )
dam = UMIN( 50, dam / 4 );
dam = UMIN( 100, dam );
damage( ch, victim, dam, sn );
return;
}
void spell_heal( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
victim->hit = UMIN( victim->hit + 100, victim->max_hit );
update_pos( victim );
send_to_char( "A warm feeling fills your body.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
/*
* Spell for mega1.are from Glop/Erkenbrand.
*/
void spell_high_explosive( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
dam = number_range( 30, 120 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_identify( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA *paf;
char buf[MAX_STRING_LENGTH];
sprintf( buf,
"Object '%s' is type %s, extra flags %s.\n\rWeight is %d, value is %d.\n\r",
obj->name,
item_type_name( obj ),
extra_bit_name( obj->extra_flags ),
obj->weight,
obj->cost );
send_to_char( buf, ch );
if( IS_SET( obj->item_type, ITEM_SCROLL ) )
{
sprintf( buf, "Level %d spells of:", obj->scroll->level );
send_to_char( buf, ch );
if( obj->scroll->spell[0] >= 0 && obj->scroll->spell[0] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->scroll->spell[0]].name, ch );
send_to_char( "'", ch );
}
if( obj->scroll->spell[1] >= 0 && obj->scroll->spell[1] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->scroll->spell[1]].name, ch );
send_to_char( "'", ch );
}
if( obj->scroll->spell[2] >= 0 && obj->scroll->spell[2] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->scroll->spell[2]].name, ch );
send_to_char( "'", ch );
}
if( obj->scroll->spell[3] >= 0 && obj->scroll->spell[3] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->scroll->spell[3]].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
}
if( IS_SET( obj->item_type, ITEM_POTION ) )
{
sprintf( buf, "Level %d spells of:", obj->potion->level );
send_to_char( buf, ch );
if ( obj->potion->spell[0] >= 0 && obj->potion->spell[0] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->potion->spell[0]].name, ch );
send_to_char( "'", ch );
}
if ( obj->potion->spell[1] >= 0 && obj->potion->spell[1] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->potion->spell[1]].name, ch );
send_to_char( "'", ch );
}
if ( obj->potion->spell[2] >= 0 && obj->potion->spell[2] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->potion->spell[2]].name, ch );
send_to_char( "'", ch );
}
if ( obj->potion->spell[3] >= 0 && obj->potion->spell[3] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->potion->spell[3]].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
}
if( IS_SET( obj->item_type, ITEM_PILL ) )
{
sprintf( buf, "Level %d spells of:", obj->pill->level );
send_to_char( buf, ch );
if ( obj->pill->spell[0] >= 0 && obj->pill->spell[0] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->pill->spell[0]].name, ch );
send_to_char( "'", ch );
}
if ( obj->pill->spell[1] >= 0 && obj->pill->spell[1] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->pill->spell[1]].name, ch );
send_to_char( "'", ch );
}
if ( obj->pill->spell[2] >= 0 && obj->pill->spell[2] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->pill->spell[2]].name, ch );
send_to_char( "'", ch );
}
if ( obj->pill->spell[3] >= 0 && obj->pill->spell[3] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->pill->spell[3]].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
}
if( IS_SET( obj->item_type, ITEM_WAND ) )
{
sprintf( buf, "Wand has %d(%d) charges of level %d",
obj->wand->charges, obj->wand->max, obj->wand->level );
send_to_char( buf, ch );
if( obj->wand->spell >= 0 && obj->wand->spell < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->wand->spell].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
}
if( IS_SET( obj->item_type, ITEM_STAFF ) )
{
sprintf( buf, "Staff has %d(%d) charges of level %d",
obj->staff->charges, obj->staff->max, obj->staff->level );
send_to_char( buf, ch );
if( obj->staff->spell >= 0 && obj->staff->spell < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->staff->spell].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
}
if( IS_SET( obj->item_type, ITEM_WEAPON ) )
{
sprintf( buf, "Damage is %dd%d+%d (average %d).\n\r",
obj->weapon->damage[0],
obj->weapon->damage[1],
obj->weapon->damage[2],
( ( 1 + obj->weapon->damage[1] )
* obj->weapon->damage[0] / 2 ) + obj->weapon->damage[2] );
send_to_char( buf, ch );
}
if( IS_SET( obj->item_type, ITEM_ARMOUR ) )
{
sprintf( buf, "Armour class is %d.\n\r", obj->armour->ac[0] );
send_to_char( buf, ch );
}
for( paf = obj->pIndexData->affected ; paf ; paf = paf->next )
{
if( paf->location != APPLY_NONE
&& paf->modifier != 0 )
{
sprintf( buf, "Affects %s by %d.\n\r",
affect_loc_name( paf->location ),
paf->modifier );
send_to_char( buf, ch );
}
}
for( paf = obj->affected ; paf ; paf = paf->next )
{
if( paf->location != APPLY_NONE
&& paf->modifier != 0 )
{
sprintf( buf, "Affects %s by %d.\n\r",
affect_loc_name( paf->location ),
paf->modifier );
send_to_char( buf, ch );
}
}
return;
}
void spell_infravision( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_INFRARED) )
return;
act( "$n's eyes glow red.\n\r", ch, NULL, NULL, TO_ROOM );
af.type = sn;
af.duration = 2 * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_INFRARED;
affect_to_char( victim, &af );
send_to_char( "Your eyes glow red.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_INVISIBLE) )
return;
act( "$n fades out of existence.", victim, NULL, NULL, TO_ROOM );
af.type = sn;
af.duration = 24;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_INVISIBLE;
affect_to_char( victim, &af );
send_to_char( "You fade out of existence.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_know_alignment( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
char *msg;
int ap;
ap = victim->alignment;
if ( ap > 700 ) msg = "$N has an aura as white as the driven snow.";
else if ( ap > 350 ) msg = "$N is of excellent moral character.";
else if ( ap > 100 ) msg = "$N is often kind and thoughtful.";
else if ( ap > -100 ) msg = "$N doesn't have a firm moral commitment.";
else if ( ap > -350 ) msg = "$N lies to $S friends.";
else if ( ap > -700 ) msg = "$N's slash DISEMBOWELS you!";
else msg = "I'd rather just not say anything at all about $N.";
act( msg, ch, NULL, victim, TO_CHAR );
return;
}
void spell_lightning_bolt( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
0, 0, 0, 0, 0, 0, 0, 0, 25, 28,
31, 34, 37, 40, 40, 41, 42, 42, 43, 44,
44, 45, 46, 46, 47, 48, 48, 49, 50, 50,
51, 52, 52, 53, 54, 54, 55, 56, 56, 57,
58, 58, 59, 60, 60, 61, 62, 62, 63, 64
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_locate_object( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj;
OBJ_DATA *in_obj;
char buf[MAX_INPUT_LENGTH];
char *buf1 = NULL;
int count = 0;
bool found = FALSE;
for( obj = object_list ; obj ; obj = obj->next )
{
if( !can_see_obj( ch, obj )
|| !is_name_old( target_name, obj->name ) )
continue;
found = TRUE;
for( in_obj = obj ; in_obj->in_obj ; in_obj = in_obj->in_obj )
;
if( in_obj->carried_by )
{
if( !IS_NPC( in_obj->carried_by ) )
continue;
sprintf( buf, "%s carried by %s.\n\r",
obj->short_descr,
PERS( in_obj->carried_by, ch ) );
}
else
{
sprintf( buf, "%s in %s.\n\r",
obj->short_descr,
in_obj->in_room ? "somewhere" : in_obj->in_room->name );
}
buf[0] = UPPER( buf[0] );
str_cat( &buf1, buf );
count++;
if( count > 100 )
break;
}
if( !found )
send_to_char_bw( "Nothing like that in hell, earth, or heaven.\n\r", ch );
page_to_char( buf1, ch );
if( buf1 )
free( buf1 );
return;
}
void spell_magic_missile( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const sh_int dam_each[] =
{
0,
3, 3, 4, 4, 5, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 12, 12, 12, 12, 12,
13, 13, 13, 13, 13, 14, 14, 14, 14, 14
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_mass_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
AFFECT_DATA af;
CHAR_DATA *gch;
for ( gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
{
if ( !is_same_group( gch, ch ) || IS_AFFECTED(gch, AFF_INVISIBLE) )
continue;
act( "$n slowly fades out of existence.", gch, NULL, NULL, TO_ROOM );
send_to_char( "You slowly fade out of existence.\n\r", gch );
af.type = sn;
af.duration = 24;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_INVISIBLE;
affect_to_char( gch, &af );
}
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_null( int sn, int level, CHAR_DATA *ch, void *vo )
{
send_to_char( "That's not a spell!\n\r", ch );
return;
}
void spell_pass_door( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_PASS_DOOR) )
return;
af.type = sn;
af.duration = number_fuzzy( level / 4 );
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_PASS_DOOR;
affect_to_char( victim, &af );
act( "$n turns translucent.", victim, NULL, NULL, TO_ROOM );
send_to_char( "You turn translucent.\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;
if ( saves_spell( level, victim ) )
return;
af.type = sn;
af.duration = level;
af.location = APPLY_STR;
af.modifier = -2;
af.bitvector = AFF_POISON;
affect_join( victim, &af );
send_to_char( "You feel very sick.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_protection( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_PROTECT) )
return;
af.type = sn;
af.duration = 24;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_PROTECT;
affect_to_char( victim, &af );
send_to_char( "You feel protected.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_refresh( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
victim->move = UMIN( victim->move + level, victim->max_move );
send_to_char( "You feel less tired.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_remove_curse( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
if ( is_affected( victim, gsn_curse ) )
{
affect_strip( victim, gsn_curse );
send_to_char( "You feel better.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
}
return;
}
void spell_sanctuary( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_SANCTUARY) )
return;
af.type = sn;
af.duration = number_fuzzy( level / 8 );
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_SANCTUARY;
affect_to_char( victim, &af );
act( "$n is surrounded by a white aura.", victim, NULL, NULL, TO_ROOM );
send_to_char( "You are surrounded by a white aura.\n\r", victim );
return;
}
void spell_shield( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = 8 + level;
af.location = APPLY_AC;
af.modifier = -20;
af.bitvector = 0;
affect_to_char( victim, &af );
act( "$n is surrounded by a force shield.", victim, NULL, NULL, TO_ROOM );
send_to_char( "You are surrounded by a force shield.\n\r", victim );
return;
}
void spell_shocking_grasp( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
static const int dam_each[] =
{
0,
0, 0, 0, 0, 0, 0, 20, 25, 29, 33,
36, 39, 39, 39, 40, 40, 41, 41, 42, 42,
43, 43, 44, 44, 45, 45, 46, 46, 47, 47,
48, 48, 49, 49, 50, 50, 51, 51, 52, 52,
53, 53, 54, 54, 55, 55, 56, 56, 57, 57
};
int dam;
level = UMIN(level, sizeof(dam_each)/sizeof(dam_each[0]) - 1);
level = UMAX(0, level);
dam = number_range( dam_each[level] / 2, dam_each[level] * 2 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
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)
|| saves_spell( level, victim ) )
return;
af.type = sn;
af.duration = 4 + level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_SLEEP;
affect_join( victim, &af );
if ( IS_AWAKE(victim) )
{
send_to_char( "You feel very sleepy ..... zzzzzz.\n\r", victim );
act( "$n goes to sleep.", victim, NULL, NULL, TO_ROOM );
victim->position = POS_SLEEPING;
}
return;
}
void spell_stone_skin( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
if ( is_affected( ch, sn ) )
return;
af.type = sn;
af.duration = level;
af.location = APPLY_AC;
af.modifier = -40;
af.bitvector = 0;
affect_to_char( victim, &af );
act( "$n's skin turns to stone.", victim, NULL, NULL, TO_ROOM );
send_to_char( "Your skin turns to stone.\n\r", victim );
return;
}
void spell_summon( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim;
if ( ( victim = get_char_world( ch, target_name ) ) == NULL
|| victim == ch
|| victim->in_room == NULL
|| IS_SET(victim->in_room->room_flags, ROOM_SAFE)
|| IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
|| IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
|| IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
|| victim->fighting != NULL
|| victim->in_room->area != ch->in_room->area
|| (IS_NPC(victim) && saves_spell( level, victim ) ) )
{
send_to_char( "You failed.\n\r", ch );
return;
}
act( "$n disappears suddenly.", victim, NULL, NULL, TO_ROOM );
char_from_room( victim );
char_to_room( victim, ch->in_room );
act( "$n arrives suddenly.", victim, NULL, NULL, TO_ROOM );
act( "$N has summoned you!", ch, NULL, victim, TO_VICT );
do_look( victim, "auto" );
return;
}
void spell_teleport( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_INDEX_DATA *pRoomIndex;
if ( victim->in_room == NULL
|| IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
|| ( !IS_NPC(ch) && victim->fighting != NULL )
|| ( victim != ch
&& ( saves_spell( level, victim ) || saves_spell( level, victim ) ) ) )
{
send_to_char( "You failed.\n\r", ch );
return;
}
for ( ; ; )
{
pRoomIndex = get_room_index( number_range( 0, 65535 ) );
if ( pRoomIndex != NULL )
if ( !IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE)
&& !IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY) )
break;
}
act( "$n slowly fades out of existence.", victim, NULL, NULL, TO_ROOM );
char_from_room( victim );
char_to_room( victim, pRoomIndex );
act( "$n slowly fades into existence.", victim, NULL, NULL, TO_ROOM );
do_look( victim, "auto" );
return;
}
void spell_ventriloquate( int sn, int level, CHAR_DATA *ch, void *vo )
{
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char speaker[MAX_INPUT_LENGTH];
CHAR_DATA *vch;
target_name = one_argument( target_name, speaker );
sprintf( buf1, "%s says '%s'.\n\r", speaker, target_name );
sprintf( buf2, "Someone makes %s say '%s'.\n\r", speaker, target_name );
buf1[0] = UPPER(buf1[0]);
for ( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
{
if ( !is_name( speaker, vch->name ) )
send_to_char( saves_spell( level, vch ) ? buf2 : buf1, vch );
}
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 ) )
return;
af.type = sn;
af.duration = level / 2;
af.location = APPLY_STR;
af.modifier = -2;
af.bitvector = 0;
affect_to_char( victim, &af );
send_to_char( "You feel weaker.\n\r", victim );
if ( ch != victim )
send_to_char( "Ok.\n\r", ch );
return;
}
/*
* This is for muds that _want_ scrolls of recall.
* Ick.
*/
void spell_word_of_recall( int sn, int level, CHAR_DATA *ch, void *vo )
{
do_recall( (CHAR_DATA *) vo, "" );
return;
}
/*
* NPC spells.
*/
void spell_acid_breath( 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;
int hpch;
if( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
{
for( obj_lose = ch->carrying ; obj_lose ; obj_lose = obj_next )
{
int iWear;
obj_next = obj_lose->next_content;
if( number_bits( 2 ) != 0 )
continue;
if( IS_SET( obj_lose->item_type, ITEM_CONTAINER ) )
{
act( "$p fumes and dissolves!",
victim, obj_lose, NULL, TO_CHAR );
extract_obj( obj_lose );
}
else if( IS_SET( obj_lose->item_type, ITEM_ARMOUR ) )
{
if( obj_lose->armour->ac[0] > 0 )
{
act( "$p is pitted and etched!",
victim, obj_lose, NULL, TO_CHAR );
if( ( iWear = obj_lose->wear_loc ) != WEAR_NONE )
victim->armour -= apply_ac( obj_lose, iWear );
obj_lose->armour->ac[0] -= 1;
obj_lose->cost = 0;
if( iWear != WEAR_NONE )
victim->armour += apply_ac( obj_lose, iWear );
}
}
}
}
hpch = UMAX( 10, ch->hit );
dam = number_range( hpch/16+1, hpch/8 );
if( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_fire_breath( 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;
int hpch;
if( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
{
for( obj_lose = victim->carrying ; obj_lose ; obj_lose = obj_next )
{
char *msg;
obj_next = obj_lose->next_content;
if( number_bits( 2 ) != 0 )
continue;
if( IS_SET( obj_lose->item_type, ITEM_CONTAINER ) )
{
msg = "$p ignites and burns!";
}
else if( IS_SET( obj_lose->item_type, ITEM_POTION ) )
{
msg = "$p bubbles and boils!";
}
else if( IS_SET( obj_lose->item_type, ITEM_SCROLL ) )
{
msg = "$p crackles and burns!";
}
else if( IS_SET( obj_lose->item_type, ITEM_STAFF ) )
{
msg = "$p smokes and chars!";
}
else if( IS_SET( obj_lose->item_type, ITEM_WAND ) )
{
msg = "$p sparks and sputters!";
}
else if( IS_SET( obj_lose->item_type, ITEM_FOOD ) )
{
msg = "$p blackens and crisps!";
}
else if( IS_SET( obj_lose->item_type, ITEM_PILL ) )
{
msg = "$p melts and drips!";
}
else
continue;
act( msg, victim, obj_lose, NULL, TO_CHAR );
extract_obj( obj_lose );
}
}
hpch = UMAX( 10, ch->hit );
dam = number_range( hpch/16+1, hpch/8 );
if( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void spell_frost_breath( 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;
int hpch;
if( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
{
for( obj_lose = victim->carrying ; obj_lose ; obj_lose = obj_next )
{
char *msg;
obj_next = obj_lose->next_content;
if ( number_bits( 2 ) != 0 )
continue;
if( IS_SET( obj_lose->item_type, ITEM_CONTAINER )
|| IS_SET( obj_lose->item_type, ITEM_DRINK_CON )
|| IS_SET( obj_lose->item_type, ITEM_POTION ) )
msg = "$p freezes and shatters!";
else
continue;
act( msg, victim, obj_lose, NULL, TO_CHAR );
extract_obj( obj_lose );
}
}
hpch = UMAX( 10, ch->hit );
dam = number_range( hpch/16+1, hpch/8 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
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 != NULL; vch = vch_next )
{
vch_next = vch->next_in_room;
if ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) )
{
hpch = UMAX( 10, ch->hit );
dam = number_range( hpch/16+1, hpch/8 );
if ( saves_spell( level, vch ) )
dam /= 2;
damage( ch, vch, dam, sn );
}
}
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/16+1, hpch/8 );
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}