/*___________________________________________________________________________*
)()( 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_misc.c ||
|| General magic code and miscellaneous spells. ||
*_/<>\_________________________________________________________________/<>\_*/
#include <math.h>
#include "mud.h"
#include "event.h"
/*
* Local functions.
*/
void say_spell args( ( CHAR_DATA *ch, int sn ) );
void flood_room args( ( ROOM_INDEX_DATA *room ) );
/* external */
void raw_kill args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
/*
* The kludgy global is for spells who want more stuff from command line.
*/
const char *target_name;
const char * const magic_name[] =
{
"air", "earth", "fire", "spirit", "water", "generic"
};
const char * const magic_colour[] =
{
"&c", "&y", "&r", "&w", "&b", "&g"
};
/*
* Lookup a skill by name.
*/
int skill_lookup( const char *name )
{
int sn;
if( !name )
return -1;
for( sn = 0; sn < MAX_SKILL; sn++ )
{
if( !skill_table[sn].name )
break;
if( LOWER( name[0] ) == LOWER( skill_table[sn].name[0] )
&& !str_prefix( name, skill_table[sn].name ) )
return sn;
}
return -1;
}
/*
* Utter mystical words for an sn.
*/
void say_spell( CHAR_DATA *ch, int sn )
{
CHAR_DATA *rch;
const char *pName;
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
int iSyl;
int length;
struct syl_type
{
const char *old;
const 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" },
{ "ea", "juma" }, { "th", "ich" },
{ "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" }, { "", "" }
};
if( !IS_NPC( ch ) && IS_SET( ch->pcdata->pc_bits, PC_BIT_RACIAL ) )
return;
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, "&g$n utters the words, '%s'.", buf );
sprintf( buf, "&g$n utters the words, '%s'.", skill_table[sn].name );
for( rch = ch->in_room->people; rch; rch = rch->next_in_room )
{
if( rch != ch && IS_AWAKE( rch ) )
act( ch->class == rch->class ? buf : buf2, ch, NULL, rch, TO_VICT );
}
return;
}
/*
* Compute a saving throw.
*/
bool saves_spell( int level, CHAR_DATA *ch, CHAR_DATA *victim, int sn )
{
int i, total = 1, sphere[MAGIC_MAX];
int save = 0;
for( i = 0; i < MAGIC_MAX; ++i )
{
if( skill_table[sn].min_mana[i] > 0 )
total += sphere[i] = skill_table[sn].min_mana[i];
}
for( i = 0; i < MAGIC_MAX; ++i )
{
if( ( sphere[i] = sphere[i] * 1000 / total ) > 0 )
save += sphere[i] * ( get_magic( victim, i ) - get_magic( ch, i ) );
}
/* Int/wis mod, int to damage, wis to save.
* Equal at 20 int/20 wis. */
save += get_curr_wis( victim ) - get_curr_int( ch ) * 2 + 20;
save += get_magic_resist( victim ) * 25;
save = 256 * atan( (double)save / 6200 ) / M_PI + 128;
return number_bits( 8 ) < URANGE( 10, save, 246 );
}
bool saves_dispel( int level, AFFECT_DATA *af, CHAR_DATA *victim, CHAR_DATA *ch )
{
int save = 100;
save += 2 * ( level - af->level );
/* Int/Wis mods. */
save += ( get_curr_wis( victim ) - get_curr_int( ch ) * 2 + 20 ) / 2;
if( af->duration > 0 )
save -= af->duration;
return number_bits( 7 ) < URANGE( 10, save, 246 );
}
void do_quicken( CHAR_DATA *ch, const char *argument )
{
if( IS_NPC( ch ) )
return;
if( !can_use( ch, gsn_quicken ) )
{
send_to_char( "You know nothing of quickening.\n\r", ch );
return;
}
if( !str_cmp( argument, "on" )
|| !IS_SET( ch->pcdata->pc_bits, PC_BIT_QUICKEN ) )
SET_BIT( ch->pcdata->pc_bits, PC_BIT_QUICKEN );
else
REMOVE_BIT( ch->pcdata->pc_bits, PC_BIT_QUICKEN );
if( IS_SET( ch->pcdata->pc_bits, PC_BIT_QUICKEN ) )
send_to_char( "You will now attempt to quicken your spells.\n\r", ch );
else
send_to_char( "You now aren't quickening your spells.\n\r", ch );
return;
}
void do_surge( CHAR_DATA *ch, const char *argument )
{
if( IS_NPC( ch ) )
return;
if( !can_use( ch, gsn_surge ) )
{
send_to_char( "You know nothing of surging.\n\r", ch );
return;
}
if( !str_cmp( argument, "on" )
|| !IS_SET( ch->pcdata->pc_bits, PC_BIT_SURGE ) )
SET_BIT( ch->pcdata->pc_bits, PC_BIT_SURGE );
else
REMOVE_BIT( ch->pcdata->pc_bits, PC_BIT_SURGE );
if( IS_SET( ch->pcdata->pc_bits, PC_BIT_SURGE ) )
send_to_char( "You will now attempt to surge your spells.\n\r", ch );
else
send_to_char( "You now aren't surging your spells.\n\r", ch );
return;
}
void do_cast( CHAR_DATA *ch, const char *argument )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
int sn;
if( IS_NPC( ch ) )
return;
target_name = one_argument( argument, arg1 );
one_argument( target_name, arg2 );
if( arg1[0] == '\0' )
{
send_to_char( "Cast which what where?\n\r", ch );
return;
}
if( ( sn = skill_lookup( arg1 ) ) <= 0
|| !can_use( ch, sn ) || skill_table[sn].spell_fun == spell_null )
{
act( "&yYou haven't learnt how to cast $t yet!", ch, arg1, NULL,
TO_CHAR );
return;
}
if( ch->position < skill_table[sn].minimum_position )
{
send_to_char( "You can't concentrate enough.\n\r", ch );
return;
}
cast_spell( ch, sn, arg2 );
return;
}
void mp_cast( CHAR_DATA *ch, const char *argument )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
int sn;
if( !IS_NPC( ch ) )
{
bad_command( ch );
return;
}
target_name = one_argument( argument, arg1 );
one_argument( target_name, arg2 );
if( arg1[0] == '\0' )
{
send_to_char( "Cast which what where?\n\r", ch );
return;
}
if( ( sn = skill_lookup( arg1 ) ) <= 0
|| !can_prac( ch, sn ) || skill_table[sn].spell_fun == spell_null )
{
send_to_char( "You can't cast that.\n\r", ch );
return;
}
cast_spell( ch, sn, arg2 );
return;
}
void drain_gems( CHAR_DATA *ch )
{
OBJ_DATA *obj;
int i;
int take;
for( i = 0; i < MAGIC_MAX; ++i )
{
if( ch->mana[i] >= 0 )
continue;
take = ch->mana[i];
if( ( obj = get_held( ch, ITEM_GEM, TRUE ) )
&& obj->value[0] == i )
{
obj->value[2] += take;
take = obj->value[2];
if( obj->value[2] < 0 )
{
act( "All the energy drains from $p and it shatters.",
ch, obj, NULL, TO_ALL );
extract_obj( obj );
}
}
if( take < 0 && ( obj = get_held( ch, ITEM_GEM, FALSE ) )
&& obj->value[0] == i )
{
obj->value[2] += take;
if( obj->value[2] < 0 )
{
act( "All the energy drains from $p and it shatters.",
ch, obj, NULL, TO_ALL );
extract_obj( obj );
}
}
ch->mana[i] = 0;
}
}
void take_generic_mana( CHAR_DATA *ch, int amount )
{
int i, remaining = amount;
for( i = 0; remaining > 0 && i < amount; ++i )
{
if( ch->mana[i % 5] > 0 )
{
ch->mana[i % 5]--;
remaining--;
}
else if( amount > 100000000 )
{
bug( "Taking mana that doesn't exist from %s [%d].",
ch->name, total_mana( ch->mana ) );
return;
}
else
amount++;
}
}
void cast_spell( CHAR_DATA *ch, int sn, const char *arg2 )
{
void *vo;
OBJ_DATA *obj;
CHAR_DATA *victim;
int mana[MAGIC_MAX + 1], spare[MAGIC_MAX], channel = -1, i;
bool success, gem = FALSE;
if( IS_AFFECTED( ch, AFF_MUTE )
|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE ) )
{
send_to_char( "Your lips move but no sound comes out.\n\r", ch );
return;
}
if( IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
{
send_to_char( "A heavy silence fills the room as you open your mouth.\n\r", ch );
return;
}
for( obj = ch->carrying; obj; obj = obj->next_content )
{
if( obj->deleted || obj->wear_loc == WEAR_NONE )
continue;
if( IS_SET( obj->extra_flags, ITEM_NO_CAST ) )
{
send_to_char( "Your armour restricts you from casting any spells.\n\r", ch );
return;
}
}
for( i = 0; i < MAGIC_MAX + 1; ++i )
mana[i] = mana_cost( ch, sn, i );
if( !IS_NPC( ch )
&& IS_SET( skill_table[sn].skill_type, SKILL_TYPE_MAGIC )
&& IS_SET( ch->pcdata->pc_bits, PC_BIT_SURGE ) )
{
for( i = 0; i < MAGIC_MAX + 1; ++i )
mana[i] *= 3;
}
if( !IS_NPC( ch )
&& IS_SET( ch->pcdata->pc_bits, PC_BIT_QUICKEN ) )
{
for( i = 0; i < MAGIC_MAX + 1; ++i )
mana[i] = mana[i] * 5 / 2;
}
/*
* Locate targets.
*/
victim = NULL;
vo = NULL;
switch( skill_table[sn].target )
{
default:
bug( "Do_cast: bad target for sn %d.", sn );
return;
case TAR_IGNORE:
break;
case TAR_CHAR_OFFENSIVE:
if( !( victim = find_target( ch, arg2, "Cast the spell on" ) ) )
return;
vo = (void *)victim;
break;
case TAR_CHAR_SELF:
if( !IS_IMMORTAL( ch ) )
{
if( arg2[0] != '\0' && !is_char_name( ch, arg2 ) )
{
send_to_char( "The focus of this spell is directed inwards.\n\r", ch );
return;
}
vo = (void *)ch;
break;
}
/*
* Imms can cast self-only on others, so we let them drop through
* to the next section.
*/
case TAR_CHAR_DEFENSIVE:
if( arg2[0] == '\0' )
{
victim = ch;
}
else
{
if( !( victim = get_char_room( ch, arg2 ) ) )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
}
vo = (void *)victim;
break;
case TAR_OBJ_INV:
if( arg2[0] == '\0' )
{
send_to_char( "What should the spell be cast upon?\n\r", ch );
return;
}
if( !( obj = get_obj_carry( ch, arg2 ) ) )
{
send_to_char( "You are not carrying that.\n\r", ch );
return;
}
vo = (void *)obj;
break;
}
if( total_mana( ch->mana ) - total_mana( mana ) - mana[MAGIC_GENERIC] < 0 )
{
send_to_char( "You have insufficient mana.\n\r", ch );
return;
}
for( i = 0; i < MAGIC_MAX; ++i )
{
spare[i] = ch->mana[i] - mana[i];
if( spare[i] < 0 && ( obj = get_held( ch, ITEM_GEM, TRUE ) )
&& obj->value[0] == i )
{
gem = TRUE;
spare[i] += obj->value[2];
}
if( spare[i] < 0 && ( obj = get_held( ch, ITEM_GEM, FALSE ) )
&& obj->value[0] == i )
{
gem = TRUE;
spare[i] += obj->value[2];
}
if( spare[i] < 0 )
{
if( IS_NPC( ch ) || ch->pcdata->learned[gsn_channel] <= 0 )
{
charprintf( ch, "You don't have enough %s mana.\n\r",
magic_name[i] );
return;
}
if( channel >= 0 )
{
charprintf( ch, "You don't have enough %s or %s mana.\n\r",
magic_name[channel], magic_name[i] );
return;
}
channel = i;
}
}
if( channel >= 0 )
{
if( get_magic( ch, channel ) * 5 + spare[channel] < 0 )
{
charprintf( ch, "You can only channel %d %s mana.\n\r",
get_magic( ch, channel ) * 5, magic_name[channel] );
return;
}
/* character's mana - spell cost - generic - amount to channel > 0 */
if( total_mana( ch->mana ) - total_mana( mana )
- mana[MAGIC_GENERIC] + spare[channel] < 0 )
{
charprintf( ch, "You have insufficient mana to channel.\n\r" );
return;
}
charprintf( ch, "You channel mana into the %s sphere.\n\r",
magic_name[channel] );
/* reduce the mana cost for the sphere so they can afford it */
mana[channel] += spare[channel];
/* this is the increased cost for channelling */
spare[channel] = spare[channel] * 2;
while( spare[channel] < 0 )
{
i = number_range( 0, MAGIC_MAX - 1 );
if( spare[i] <= 0 )
continue;
spare[channel]++; /* ok reduce the debt */
spare[i]--; /* we now have less spare in this sphere */
mana[i]++; /* increase the mana cost for this sphere */
}
}
if( str_cmp( skill_table[sn].name, "ventriloquate" ) )
say_spell( ch, sn );
if( !IS_NPC( ch )
&& IS_SET( ch->pcdata->pc_bits, PC_BIT_QUICKEN )
&& get_success( ch, gsn_quicken, 100 ) )
WAIT_STATE( ch, skill_table[sn].beats / 2 );
else
WAIT_STATE( ch, skill_table[sn].beats );
if( !get_success( ch, sn, 100 ) )
{
success = FALSE;
send_to_char( "Your concentration slips at the last moment.\n\r", ch );
act( "Your mana is drained by the incomplete $t spell.", ch,
skill_table[sn].name, NULL, TO_CHAR );
for( i = 0; i < MAGIC_MAX; ++i )
ch->mana[i] -= mana[i] / 2;
if( gem )
drain_gems( ch );
take_generic_mana( ch, mana[MAGIC_GENERIC] / 2 );
}
else
{
success = TRUE;
/*
* The drunken man may slur his words a little,
* this has a slightly unpredictable effect.
* --Symposium
*/
if( !IS_NPC( ch )
&& UMIN( 80, ch->pcdata->condition[COND_DRUNK] / 10 - 25 )
> number_percent( ) )
{
int drunk_sn;
do
{
drunk_sn = number_range( 1, MAX_SKILL - 1 );
}
while( skill_table[sn].target != skill_table[drunk_sn].target );
if( ( !can_use( ch, drunk_sn ) && number_bits( 6 ) != 0 )
|| number_bits( 3 ) != 0 )
drunk_sn = 0;
if( skill_table[sn].target == TAR_IGNORE )
drunk_sn = 0;
act( "$n gestures drunkenly and mumbles something.",
ch, NULL, NULL, TO_ROOM );
act( "You drunkenly slur something, you are soooo drunk!",
ch, NULL, NULL, TO_CHAR );
sn = drunk_sn;
}
for( i = 0; i < MAGIC_MAX; ++i )
ch->mana[i] -= mana[i];
if( gem )
drain_gems( ch );
take_generic_mana( ch, mana[MAGIC_GENERIC] );
( *skill_table[sn].spell_fun )
( sn, URANGE( 1, ch->level, LEVEL_HERO * 2 ), ch, vo );
if( !ch->deleted && victim && !victim->deleted && IS_NPC( victim ) )
{
CHAR_DATA *vch;
for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if( !vch->deleted && victim == vch )
{
mprog_cast_trigger( victim, ch, sn );
break;
}
}
}
}
target_name = &str_empty[0];
if( skill_table[sn].target == TAR_CHAR_OFFENSIVE
&& victim->master != ch && victim != ch && IS_AWAKE( victim )
&& ( success || number_percent( ) < get_curr_int( victim ) * 2 ) )
{
CHAR_DATA *vch;
for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if( !vch->deleted && victim == vch && !victim->fighting )
{
multi_hit( victim, ch, TYPE_UNDEFINED );
break;
}
}
}
return;
}
void do_racial( CHAR_DATA *ch, const char *argument )
{
AFFECT_DATA *af;
char arg[MAX_INPUT_LENGTH];
char buf[MAX_INPUT_LENGTH];
const char *sk;
int sn = -1;
target_name = argument = one_argument( argument, arg );
if( IS_NPC( ch ) || !race_table[ch->race].racial_skill )
{
send_to_char( "You don't know how.\n\r", ch );
return;
}
if( arg[0] == '\0' || !str_cmp( arg, "help" ) )
{
charprintf( ch, "&gYou have access to the racial skill(s): &y%s&n\n\r",
race_table[ch->race].racial_skill );
return;
}
sk = race_table[ch->race].racial_skill;
while( sk[0] != '\0' && sn < 0 )
{
sk = one_argument( sk, buf );
if( !str_prefix( arg, buf ) )
sn = skill_lookup( buf );
}
if( sn <= 0 )
{
send_to_char( "You don't have permission.\n\r", ch );
return;
}
for( af = ch->affected; af; af = af->next )
{
/* may as well let imms use their racial a few times */
if( af->type == gsn_racial_fatigue && af->location == sn
&& !af->deleted && !IS_IMMORTAL( ch ) )
{
send_to_char( "You don't feel up to it yet.\n\r", ch );
return;
}
}
if( ch->position < skill_table[sn].minimum_position )
{
send_to_char( "You can't concentrate enough.\n\r", ch );
return;
}
act( "$n concentrates briefly.", ch, NULL, NULL, TO_ROOM );
SET_BIT( ch->pcdata->pc_bits, PC_BIT_RACIAL );
if( skill_table[sn].spell_fun == spell_null )
{
sprintf( buf, "\"%s\" %s",
skill_table[sn].name, argument );
interpret( ch, buf );
}
else
{
cast_spell( ch, sn, argument );
}
REMOVE_BIT( ch->pcdata->pc_bits, PC_BIT_RACIAL );
af = new_affect( );
af->type = gsn_racial_fatigue;
af->level = LEVEL_HERO;
af->location = sn;
af->modifier = 0;
af->duration = 5 + power( 10, 5, 25 - ch->level );
vzero( af->bitvector );
affect_to_char( ch, af, NULL );
ch->wait /= 2;
return;
}
void do_brandish( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *staff;
CHAR_DATA *vch;
int sn;
if( !( staff = get_held( ch, ITEM_STAFF, TRUE ) ) )
{
send_to_char( "You aren't holding a staff.\n\r", ch );
return;
}
if( ( IS_NPC( ch ) && xIS_SET( ch->act, ACT_PET ) )
|| IS_AFFECTED( ch, AFF_CHARM ) )
{
act( "You try to brandish $p, but you have no free will.",
ch, staff, NULL, TO_CHAR );
act( "$n tries to brandish $p, but has no free will.",
ch, staff, NULL, TO_ROOM );
return;
}
if( ( sn = staff->value[3] ) < 0
|| sn >= MAX_SKILL
|| skill_table[sn].spell_fun == 0 )
{
bug( "Do_brandish: bad sn %d.", sn );
return;
}
if( staff->level > ch->level + 3 )
{
send_to_char( "You are too inexperienced to use this.\n\r", ch );
return;
}
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
if( staff->value[2] > 0 )
{
CHAR_DATA *vch_next;
act( "You brandish $p.", ch, staff, NULL, TO_CHAR );
act( "$n brandishes $p.", ch, staff, NULL, TO_ROOM );
/*
Staves skill by Binky for EnvyMud, modified by Thelonius
*/
if( !IS_NPC( ch )
&& !get_success( ch, gsn_staves, 100 ) )
{
switch( number_bits( 3 ) )
{
case 0:
case 1:
case 2:
case 3:
act( "You are unable to invoke the power of $p.",
ch, staff, NULL, TO_CHAR );
act( "$n is unable to invoke the power of $p.",
ch, staff, NULL, TO_ROOM );
return;
case 4:
case 5:
case 6:
act( "You summon the power of $p, but it fizzles away.",
ch, staff, NULL, TO_CHAR );
act( "$n summons the power of $p, but it fizzles away.",
ch, staff, NULL, TO_ROOM );
if( --staff->value[2] <= 0 )
{
act( "$p blazes bright and is gone.",
ch, staff, NULL, TO_CHAR );
act( "$p blazes bright and is gone.",
ch, staff, NULL, TO_ROOM );
extract_obj( staff );
}
return;
case 7:
act( "You can't control the power of $p, and it shatters!",
ch, staff, NULL, TO_CHAR );
act( "$p shatters into tiny pieces!",
ch, staff, NULL, TO_ROOM );
/*
* damage( ) call after extract_obj in case the damage would
* have extracted ch. This is okay because we merely mark
* obj->deleted; it still retains all values until list_update.
* Sloppy? Okay, create another integer variable. ---Thelonius
*/
extract_obj( staff );
damage( ch, ch, staff->level, gsn_staves, WEAR_NONE );
return;
}
}
for( vch = ch->in_room->people; vch; vch = vch_next )
{
vch_next = vch->next_in_room;
if( vch->deleted )
continue;
switch( skill_table[sn].target )
{
default:
bug( "Do_brandish: bad target for sn %d.", sn );
return;
case TAR_IGNORE:
if( vch != ch )
continue;
break;
case TAR_CHAR_OFFENSIVE:
if( IS_NPC( ch ) ? IS_NPC( vch ) : !IS_NPC( vch ) )
continue;
break;
case TAR_CHAR_DEFENSIVE:
if( IS_NPC( ch ) ? !IS_NPC( vch ) : IS_NPC( vch ) )
continue;
break;
case TAR_CHAR_SELF:
if( vch != ch )
continue;
break;
}
obj_cast_spell( staff->value[3], staff->value[0],
ch, vch, NULL, NULL );
}
}
if( xIS_SET( staff->pIndexData->progtypes, USE_PROG ) )
oprog_percent_check( ch, staff, NULL, USE_PROG );
if( !IS_NPC( ch )
|| ( IS_NPC( ch ) && is_affected( ch, gsn_charm_person ) ) )
if( !staff->deleted && --staff->value[2] <= 0 )
{
act( "$p blazes bright and is gone.", ch, staff, NULL, TO_CHAR );
act( "$p blazes bright and is gone.", ch, staff, NULL, TO_ROOM );
extract_obj( staff );
}
return;
}
void do_quaff( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
char arg[MAX_INPUT_LENGTH];
argument = one_argument( argument, arg );
if( arg[0] == '\0' )
{
send_to_char( "Quaff what?\n\r", ch );
return;
}
if( !( obj = get_obj_carry( ch, arg ) ) )
{
send_to_char( "You do not have that potion.\n\r", ch );
return;
}
if( obj->item_type != ITEM_POTION )
{
send_to_char( "You can quaff only potions.\n\r", ch );
return;
}
act( "You quaff $p.", ch, obj, NULL, TO_CHAR );
act( "$n quaffs $p.", ch, obj, NULL, TO_ROOM );
if( obj->action && obj->action[0] )
send_to_char( obj->action, ch );
if( obj->level > ch->level + 3 )
act( "$p is too high level for you.", ch, obj, NULL, TO_CHAR );
else
{
obj_cast_spell( obj->value[1], obj->value[0], ch, ch, NULL, argument );
obj_cast_spell( obj->value[2], obj->value[0], ch, ch, NULL, argument );
obj_cast_spell( obj->value[3], obj->value[0], ch, ch, NULL, argument );
}
if( xIS_SET( obj->pIndexData->progtypes, USE_PROG ) )
oprog_percent_check( ch, obj, NULL, USE_PROG );
if( !obj->deleted
&& ( !IS_NPC( ch )
|| ( IS_NPC( ch ) && is_affected( ch, gsn_charm_person ) ) ) )
extract_obj( obj );
return;
}
void do_recite( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *scroll;
OBJ_DATA *obj;
CHAR_DATA *victim;
char arg1[MAX_INPUT_LENGTH];
argument = one_argument( argument, arg1 );
if( !( scroll = get_obj_carry( ch, arg1 ) ) )
{
send_to_char( "You do not have that scroll.\n\r", ch );
return;
}
if( scroll->item_type != ITEM_SCROLL )
{
send_to_char( "You can recite only scrolls.\n\r", ch );
return;
}
if( scroll->level > ch->level + 3 )
{
send_to_char( "You are too inexperienced to use this.\n\r", ch );
return;
}
obj = NULL;
if( argument[0] == '\0' )
{
victim = ch;
if( ch->fighting )
victim = ch->fighting;
}
else
{
victim = get_char_room( ch, argument );
obj = get_obj_here( ch, argument );
}
if( IS_AFFECTED( ch, AFF_MUTE )
|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
{
send_to_char( "Your lips move but no sound comes out.\n\r", ch );
return;
}
if( ( IS_NPC( ch ) && xIS_SET( ch->act, ACT_PET ) )
|| IS_AFFECTED( ch, AFF_CHARM ) )
{
act( "$n tries to recite $p, but has no free will.",
ch, scroll, NULL, TO_ALL );
return;
}
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
act( "$n recite$% $p.", ch, scroll, NULL, TO_ALL );
if( scroll->action && scroll->action[0] )
send_to_char( scroll->action, ch );
/*
* Scrolls skill by Binky for EnvyMud, modified by Thelonius
*/
if( !IS_NPC( ch )
&& !get_success( ch, gsn_scrolls, 100 ) )
{
switch( number_bits( 3 ) )
{
case 0:
case 1:
case 2:
case 3:
act( "$n can't understand $p at all.",
ch, scroll, NULL, TO_ALL );
return;
case 4:
case 5:
case 6:
send_to_char( "You must have said something incorrectly.\n\r",
ch );
act( "$n must have said something incorrectly.",
ch, NULL, NULL, TO_ROOM );
act( "$p blazes brightly, then is gone.",
ch, scroll, NULL, TO_CHAR );
act( "$p blazes brightly and disappears.",
ch, scroll, NULL, TO_ROOM );
extract_obj( scroll );
return;
case 7:
act(
"You completely botch the recitation, and $p bursts into flames!!",
ch, scroll, NULL, TO_CHAR );
act( "$p glows and then bursts into flame!",
ch, scroll, NULL, TO_ROOM );
/*
* damage( ) call after extract_obj in case the damage would
* have extracted ch. This is okay because we merely mark
* obj->deleted; it still retains all values until list_update.
* Sloppy? Okay, create another integer variable. ---Thelonius
*/
extract_obj( scroll );
damage( ch, ch, scroll->level, gsn_scrolls, WEAR_NONE );
return;
}
}
if( scroll->level > ch->level + 3 )
act( "$p is too high level for you.", ch, scroll, NULL, TO_CHAR );
else
{
obj_cast_spell( scroll->value[1], scroll->value[0],
ch, victim, obj, argument );
obj_cast_spell( scroll->value[2], scroll->value[0],
ch, victim, obj, argument );
obj_cast_spell( scroll->value[3], scroll->value[0],
ch, victim, obj, argument );
}
if( xIS_SET( scroll->pIndexData->progtypes, USE_PROG ) )
oprog_percent_check( ch, scroll, victim, USE_PROG );
if( !scroll->deleted
&& ( !IS_NPC( ch )
|| ( IS_NPC( ch ) && is_affected( ch, gsn_charm_person ) ) ) )
extract_obj( scroll );
return;
}
void do_zap( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *wand;
OBJ_DATA *obj;
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
int sn;
one_argument( argument, arg );
if( arg[0] == '\0' && !ch->fighting )
{
send_to_char( "Zap whom or what?\n\r", ch );
return;
}
if( !( wand = get_held( ch, ITEM_WAND, TRUE ) ) )
{
send_to_char( "You aren't holding a wand.\n\r", ch );
return;
}
if( wand->level > ch->level + 3 )
{
send_to_char( "You are too inexperienced to use this.\n\r", ch );
return;
}
obj = NULL;
if( arg[0] == '\0' )
{
if( ch->fighting )
{
victim = ch->fighting;
}
else
{
send_to_char( "Zap whom or what?\n\r", ch );
return;
}
}
else
{
if( !( victim = get_char_room( ch, arg ) )
&& !( obj = get_obj_here( ch, arg ) ) )
{
send_to_char( "You can't find it.\n\r", ch );
return;
}
}
if( ( IS_NPC( ch ) && xIS_SET( ch->act, ACT_PET ) )
|| IS_AFFECTED( ch, AFF_CHARM ) )
{
act( "You try to zap $p, but you have no free will.",
ch, wand, NULL, TO_CHAR );
act( "$n tries to zap $p, but has no free will.",
ch, wand, NULL, TO_ROOM );
return;
}
if( ( sn = wand->value[3] ) < 0
|| sn >= MAX_SKILL
|| skill_table[sn].spell_fun == 0 )
{
bug( "Do_zap: bad sn %d.", sn );
return;
}
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
if( wand->value[2] > 0 )
{
if( victim )
if( victim == ch )
{
act( "You zap yourself with $p.", ch, wand, NULL, TO_CHAR );
act( "$n zaps $mself with $p.", ch, wand, NULL, TO_ROOM );
}
else
{
act( "You zap $N with $p.", ch, wand, victim, TO_CHAR );
act( "$n zaps $N with $p.", ch, wand, victim, TO_ROOM );
}
else
{
act( "You zap $P with $p.", ch, wand, obj, TO_CHAR );
act( "$n zaps $P with $p.", ch, wand, obj, TO_ROOM );
}
/*
Wands skill by Binky for EnvyMud, modified by Thelonius
*/
if( !IS_NPC( ch )
&& !get_success( ch, gsn_wands, 100 ) )
{
switch( number_bits( 3 ) )
{
case 0:
case 1:
case 2:
case 3:
act( "You are unable to invoke the power of $p.",
ch, wand, NULL, TO_CHAR );
act( "$n is unable to invoke the power of $p.",
ch, wand, NULL, TO_ROOM );
return;
case 4:
case 5:
case 6:
act( "You summon the power of $p, but it fizzles away.",
ch, wand, NULL, TO_CHAR );
act( "$n summons the power of $p, but it fizzles away.",
ch, wand, NULL, TO_ROOM );
if( --wand->value[2] <= 0 )
{
act( "$p blazes bright and is gone.",
ch, wand, NULL, TO_CHAR );
act( "$p blazes bright and is gone.",
ch, wand, NULL, TO_ROOM );
extract_obj( wand );
}
return;
case 7:
act( "You can't control the power of $p, and it explodes!",
ch, wand, NULL, TO_CHAR );
act( "$p explodes into fragments!",
ch, wand, NULL, TO_ROOM );
/*
* damage( ) call after extract_obj in case the damage would
* have extracted ch. This is okay because we merely mark
* obj->deleted; it still retains all values until list_update.
* Sloppy? Okay, create another integer variable. ---Thelonius
*/
extract_obj( wand );
damage( ch, ch, wand->level, gsn_wands, WEAR_NONE );
return;
}
}
obj_cast_spell( wand->value[3], wand->value[0],
ch, victim, obj, argument );
}
if( xIS_SET( wand->pIndexData->progtypes, USE_PROG ) )
oprog_percent_check( ch, wand, victim, USE_PROG );
if( !IS_NPC( ch )
|| ( IS_NPC( ch ) && is_affected( ch, gsn_charm_person ) ) )
if( !wand->deleted && --wand->value[2] <= 0 )
{
act( "$p explodes into fragments.", ch, wand, NULL, TO_CHAR );
act( "$p explodes into fragments.", ch, wand, NULL, TO_ROOM );
extract_obj( wand );
}
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, const char *extra )
{
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 )
victim = ch->fighting;
if( !victim )
{
send_to_char( "You can't find them.\n\r", ch );
return;
}
if( is_safe( ch, victim ) )
return;
check_killer( ch, victim );
vo = (void *)victim;
break;
case TAR_CHAR_DEFENSIVE:
if( !victim )
victim = ch;
vo = (void *)victim;
break;
case TAR_CHAR_SELF:
vo = (void *)ch;
break;
case TAR_OBJ_INV:
if( !obj )
{
send_to_char( "You can't find that.\n\r", ch );
return;
}
vo = (void *)obj;
break;
}
if( extra )
target_name = extra;
else
target_name = "";
( *skill_table[sn].spell_fun ) ( sn, level, ch, vo );
target_name = "";
if( skill_table[sn].target == TAR_CHAR_OFFENSIVE
&& victim->master != ch && ch != victim )
{
CHAR_DATA *vch;
for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if( !vch->deleted && victim == vch && !victim->fighting )
{
multi_hit( victim, ch, TYPE_UNDEFINED );
break;
}
}
}
return;
}
/* Original Code by Todd Lair. */
/* Improvements and Modification by Jason Huang (huangjac@netcom.com). */
/* Permission to use this code is granted provided this header is */
/* retained and unaltered. */
void do_brew( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
int sn;
if( !IS_NPC( ch ) && !can_use( ch, gsn_brew ) )
{
send_to_char( "You do not know how to brew potions.\n\r", ch );
return;
}
if( argument[0] == '\0' )
{
send_to_char( "Brew what spell?\n\r", ch );
return;
}
/*
* Do we have a vial to brew potions?
*/
for( obj = ch->carrying; obj; obj = obj->next_content )
{
if( obj->item_type == ITEM_POTION
&& ( obj->wear_loc == WEAR_HOLD_L
|| obj->wear_loc == WEAR_HOLD_R ) )
break;
}
if( !obj )
{
send_to_char( "You are not holding a vial.\n\r", ch );
return;
}
if( ( sn = skill_lookup( argument ) ) < 0 )
{
send_to_char( "You don't know any spells by that name.\n\r", ch );
return;
}
if( ( skill_table[sn].target != TAR_CHAR_DEFENSIVE )
&& ( skill_table[sn].target != TAR_CHAR_SELF ) )
{
send_to_char( "You cannot brew that spell.\n\r", ch );
return;
}
act( "$n begins preparing a potion.", ch, obj, NULL, TO_ROOM );
WAIT_STATE( ch, skill_table[gsn_brew].beats );
/*
Check the skill percentage, fcn( wis,int,skill )
*/
if( !IS_NPC( ch ) && !IS_IMMORTAL( ch )
&& ( number_percent( ) > get_success( ch, gsn_brew, 120 )
|| number_percent( ) > ( ( get_curr_int( ch ) - 13 ) * 5 +
( get_curr_wis( ch ) - 13 ) * 3 ) ) )
{
act( "$p explodes violently!", ch, obj, NULL, TO_CHAR );
act( "$p explodes violently!", ch, obj, NULL, TO_ROOM );
spell_acid_blast( skill_lookup( "acid blast" ), ch->level, ch, ch );
extract_obj( obj );
return;
}
obj->level = ch->level;
obj->value[0] = ch->level - 1;
spell_imprint( sn, ch->level, ch, obj );
}
void do_scribe( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
int sn;
if( !IS_NPC( ch ) && !can_use( ch, gsn_scribe ) )
{
send_to_char( "You do not know how to scribe scrolls.\n\r", ch );
return;
}
if( argument[0] == '\0' )
{
send_to_char( "Scribe what spell?\n\r", ch );
return;
}
/*
Do we have a parchment to scribe spells?
*/
for( obj = ch->carrying; obj; obj = obj->next_content )
{
if( obj->item_type == ITEM_SCROLL
&& ( obj->wear_loc == WEAR_HOLD_L
|| obj->wear_loc == WEAR_HOLD_R ) )
break;
}
if( !obj )
{
send_to_char( "You are not holding a parchment.\n\r", ch );
return;
}
if( ( sn = skill_lookup( argument ) ) < 0 )
{
send_to_char( "You don't know any spells by that name.\n\r", ch );
return;
}
act( "$n begins writing a scroll.", ch, obj, NULL, TO_ROOM );
WAIT_STATE( ch, skill_table[gsn_scribe].beats );
/*
* Check the skill percentage, fcn( int,wis,skill )
*/
if( !IS_NPC( ch ) && !IS_IMMORTAL( ch )
&& ( number_percent( ) > get_success( ch, gsn_brew, 120 )
|| number_percent( ) > ( ( get_curr_int( ch ) - 13 ) * 5 +
( get_curr_wis( ch ) - 13 ) * 3 ) ) )
{
act( "$p bursts in flames!", ch, obj, NULL, TO_CHAR );
act( "$p bursts in flames!", ch, obj, NULL, TO_ROOM );
spell_power_6( skill_lookup( "fireball" ), ch->level, ch, ch );
extract_obj( obj );
return;
}
/*
* basically, making scrolls more potent than potions; also, scrolls
* are not limited in the choice of spells, i.e. scroll of enchant weapon
* has no analogs in potion forms --- JH
*/
obj->level = ch->level;
obj->value[0] = ch->level - 1;
spell_imprint( sn, ch->level, ch, obj );
}
void spell_imprint( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int sp_slot, i, mana[MAGIC_MAX], chance;
char buf[MAX_STRING_LENGTH];
if( skill_table[sn].spell_fun == spell_null )
{
send_to_char( "That is not a spell.\n\r", ch );
return;
}
/*
* counting the number of spells contained within.
*/
for( sp_slot = i = 1; i < 4; i++ )
if( obj->value[i] > 0 )
sp_slot++;
if( sp_slot > 3 )
{
act( "$p cannot contain any more spells.", ch, obj, NULL, TO_CHAR );
return;
}
/*
* scribe/brew costs 3 times the normal mana required to cast the spell
*/
for( i = 0; i < MAGIC_MAX; ++i )
{
mana[i] = 3 * mana_cost( ch, sn, i );
if( !IS_NPC( ch ) && ch->mana[i] < mana[i] )
{
send_to_char( "You don't have enough mana.\n\r", ch );
return;
}
}
if( !get_success( ch, sn, 100 ) )
{
send_to_char( "You lost your concentration.\n\r", ch );
for( i = 0; i < MAGIC_MAX; ++i )
ch->mana[i] -= mana[i] / 2;
return;
}
/*
* executing the imprinting process
*/
for( i = 0; i < MAGIC_MAX; ++i )
ch->mana[i] -= mana[i];
obj->value[sp_slot] = sn;
/*
* Making it successively harder to pack more spells into potions or
* scrolls - JH
*/
switch( sp_slot )
{
default:
bug( "sp_slot has more than %d spells.", sp_slot );
return;
case 1:
chance = 80;
break;
case 2:
chance = 25;
break;
case 3:
chance = 10;
break;
}
chance = power( chance, 3, get_curr_int( ch ) - 15 );
if( !IS_IMMORTAL( ch ) && number_percent( ) > chance )
{
sprintf( buf, "The magic enchantment has failed --- the %s vanishes.\n\r", flag_string( type_flags, &obj->item_type ) );
send_to_char( buf, ch );
extract_obj( obj );
return;
}
/*
* labeling the item
*/
free_string( obj->short_descr );
sprintf( buf, "a %s of ", flag_string( type_flags, &obj->item_type ) );
for( i = 1; i <= sp_slot; i++ )
if( obj->value[i] > 0 )
{
strcat( buf, skill_table[obj->value[i]].name );
( i != sp_slot ) ? strcat( buf, ", " ) : strcat( buf, "" );
}
obj->short_descr = str_dup( buf );
if( !str_str( obj->name, flag_string( type_flags, &obj->item_type ) ) )
{
sprintf( buf, "%s %s", obj->name,
flag_string( type_flags, &obj->item_type ) );
free_string( obj->name );
obj->name = str_dup( buf );
}
sprintf( buf, "You have imbued a new spell to the %s.\n\r",
flag_string( type_flags, &obj->item_type ) );
send_to_char( buf, ch );
return;
}
/*
* Enchantment functions.
* these involve some complicated functions in order to ensure that
* enchanting is adequately difficult yet not impossible.
*/
#define NORMAL_SCORE 110.0
/* a number from 10 to 110 */
int ench_brilliant( int level, int score )
{
double brill;
brill = (double)( score - NORMAL_SCORE + level / 2.0 );
brill = atan( brill ) * 100 / M_PI + 60;
return (int)brill;
}
/* a number from 0 to 512 */
int ench_normal( int level, int score )
{
double norm;
if( score > NORMAL_SCORE )
return 500 + score - NORMAL_SCORE;
else if( score < NORMAL_SCORE - level )
return 0;
norm = (double)( ( score - NORMAL_SCORE ) * 3 ) / (double)( 2 * level );
norm = 350.0 * cos( norm ) + 150.0;
return UMAX( 0, norm );
}
void animate_corpse( CHAR_DATA *ch, OBJ_DATA *cor, int sn, int level )
{
OBJ_DATA *obj;
MOB_INDEX_DATA *pMob;
CHAR_DATA *mob;
char buf[MAX_INPUT_LENGTH];
if( IS_SET( race_table[cor->value[0]].race_abilities, RACE_UNDEAD ) )
{
send_to_char( "That corpse cannot be animated at all.\n\r", ch );
send_to_char( "That has already been undead.\n\r", ch );
return;
}
switch( number_bits( 4 ) )
{
case 0: case 1: case 2: case 3: case 4:
pMob = get_mob_index( MOB_VNUM_SKELETON );
break;
default:
pMob = get_mob_index( MOB_VNUM_ZOMBIE );
break;
case 12: case 13: case 14:
pMob = get_mob_index( MOB_VNUM_MUMMY );
break;
case 15:
pMob = get_mob_index( MOB_VNUM_LICH );
break;
}
pMob->level += cor->level - 5;
mob = create_mobile( pMob );
pMob->level += 5 - cor->level;
mob->resil_mod = ( race_table[cor->value[0]].resil - 1000 ) / 2;
mob->gold = 0;
sprintf( buf, mob->name, race_table[cor->value[0]].name );
free_string( mob->name );
mob->name = str_dup( buf );
sprintf( buf, mob->short_descr, race_table[cor->value[0]].name );
free_string( mob->short_descr );
mob->short_descr = str_dup( buf );
sprintf( buf, mob->long_descr, race_table[cor->value[0]].name );
free_string( mob->long_descr );
mob->long_descr = str_dup( buf );
if( number_percent( ) < ch->level - 50 )
xSET_BIT( mob->affected_by, AFF_SANCTUARY );
if( number_percent( ) < ch->level - 50 )
xSET_BIT( mob->affected_by, AFF_FLYING );
if( !IS_NPC( ch ) && number_percent( ) > ch->pcdata->learned[sn] )
xSET_BIT( mob->act, ACT_WIMPY );
char_to_room( mob, ch->in_room );
for( obj = cor->contains; obj; obj = obj->next_content )
{
if( obj->deleted )
continue;
obj_from_obj( obj );
obj_to_char( obj, mob );
}
act( "$n gestures and $N rises from $p.", ch, cor, mob, TO_NOTVICT );
act( "You gesture and $N rises from $p.", ch, cor, mob, TO_CHAR );
extract_obj( cor );
do_wear( mob, "all" );
if( sn > 0 )
{
if( saves_spell( level, mob, ch, sn ) )
{
multi_hit( mob, ch, TYPE_UNDEFINED );
}
else
{
xSET_BIT( mob->affected_by, AFF_CHARM );
mob->master = ch;
create_char_event( mob, evn_raised_undead,
percent_fuzzy( level * 15 + 300, 12 )
* PULSE_PER_SECOND );
if( ch->fighting )
{
mob->position = POS_FIGHTING;
mob->fighting = ch->fighting;
}
}
}
}
/*
* Spell functions.
*/
void spell_animate_dead( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *cor;
if( IS_NPC( ch ) )
return;
cor = get_obj_here( ch, target_name );
if( !cor || cor->item_type != ITEM_CORPSE_NPC )
{
send_to_char( "You can't animate that.\n\r", ch );
return;
}
animate_corpse( ch, cor, sn, level );
return;
}
void spell_army_of_dark( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *mob;
int number = 1;
int i;
act( "$n wave$% dramatically and a horde of undead spring up around $m.",
ch, NULL, NULL, TO_ALL );
for( i = 0; i < ch->level; i += 20 )
if( number_bits( 1 ) == 0 )
number++;
for( mob = ch->in_room->people; mob; mob = mob->next_in_room )
{
if( IS_NPC( mob ) && mob->master == ch && number_bits( 2 ) != 0 )
number--;
}
if( number < -1 )
{
send_to_char( "There is too litle life force left in the room.\n\r",
ch );
return;
}
number = URANGE( 1, number, 10 );
for( i = 0; i < number; i++ )
{
int race;
MOB_INDEX_DATA *pMob;
char buf[MAX_STRING_LENGTH];
switch( number_bits( 4 ) )
{
case 0: case 1: case 2:
case 3: case 4:
pMob = get_mob_index( MOB_VNUM_SKELETON );
break;
default:
pMob = get_mob_index( MOB_VNUM_ZOMBIE );
break;
case 12: case 13: case 14:
pMob = get_mob_index( MOB_VNUM_MUMMY );
break;
case 15:
pMob = get_mob_index( MOB_VNUM_LICH );
break;
}
pMob->level += ch->level - 10;
mob = create_mobile( pMob );
pMob->level += 10 - ch->level;
mob->gold = 0;
race = number_range( 0, MAX_RACE - 1 );
mob->resil_mod = ( race_table[race].resil - 1000 ) / 2;
sprintf( buf, mob->name, race_table[race].name );
free_string( mob->name );
mob->name = str_dup( buf );
sprintf( buf, mob->short_descr, race_table[race].name );
free_string( mob->short_descr );
mob->short_descr = str_dup( buf );
sprintf( buf, mob->long_descr, race_table[race].name );
free_string( mob->long_descr );
mob->long_descr = str_dup( buf );
char_to_room( mob, ch->in_room );
act( "$n rises from the ground and attacks!",
mob, NULL, NULL, TO_ROOM );
if( number_bits( 3 ) == 0 )
{
multi_hit( mob, ch, TYPE_UNDEFINED );
}
else
{
xSET_BIT( mob->affected_by, AFF_CHARM );
mob->master = ch;
create_char_event( mob, evn_raised_undead,
percent_fuzzy( level * 15 + 300, 12 )
* PULSE_PER_SECOND );
if( ch->fighting )
{
mob->position = POS_FIGHTING;
mob->fighting = ch->fighting;
}
}
}
return;
}
void spell_astral( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *rch;
ROOM_INDEX_DATA *location;
rch = get_char_world( ch, target_name );
if( target_name[0] == '\0' )
{
send_to_char( "Where did you want to go?\n\r", ch );
return;
}
if( !rch || IS_NPC( rch ) )
{
send_to_char( "That character can't be found.\n\r", ch );
return;
}
if( !( location = rch->in_room ) )
{
send_to_char( "Your spell fizzles.\n\r", ch );
return;
}
if( IS_SET( location->room_flags, ROOM_SAFE )
|| room_is_private( location )
|| IS_SET( location->room_flags, ROOM_NO_PORTAL )
|| ch->in_room->area->plane != location->area->plane )
{
send_to_char( "Your spell fizzles.\n\r", ch );
return;
}
send_to_char( "You step through the astral plane.\n\r", ch );
act( "$n steps into the astral plane, disappearing totally.", ch, NULL, NULL, TO_ROOM );
char_from_room( ch );
char_to_room( ch, location );
act( "You shiver as $n steps from the astral plane.", ch, NULL, NULL, TO_ROOM );
do_look( ch, AUTOLOOK );
return;
}
void spell_awe( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *)vo;
if( victim->fighting == ch && !saves_spell( level, victim, ch, sn ) )
{
stop_fighting( victim, TRUE );
act( "$N is in AWE of you!", ch, NULL, victim, TO_CHAR );
act( "You are in AWE of $n!", ch, NULL, victim, TO_VICT );
act( "$N is in AWE of $n!", ch, NULL, victim, TO_NOTVICT );
}
return;
}
/*
* Calm spell taken straight from ROM 2.4.
*/
void spell_calm( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
int mlevel = 0;
int count = 0;
int high_level = 0;
int chance;
AFFECT_DATA af;
/* get sum of all mobile levels in the room */
for( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
{
if( vch->position == POS_FIGHTING )
{
count++;
if( IS_NPC( vch ) )
mlevel += vch->level;
else
mlevel += vch->level / 2;
high_level = UMAX( high_level, vch->level );
}
}
/* compute chance of stopping combat */
chance = 4 * level - high_level + 2 * count;
if( IS_IMMORTAL( ch ) ) /* always works */
mlevel = 0;
if( number_range( 0, chance ) >= mlevel ) /* hard to stop large fights */
{
for( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
{
if( IS_AFFECTED( vch, AFF_BERSERK ) )
continue;
send_to_char( "A wave of calm passes over you.\n\r", vch );
if( vch->fighting || vch->position == POS_FIGHTING )
stop_fighting( vch, FALSE );
if( IS_AFFECTED( vch, AFF_CALM ) || saves_spell( level, vch, ch, sn ) )
continue;
af.type = sn;
af.level = level;
af.duration = level / 4;
af.location = APPLY_HITROLL;
if( !IS_NPC( vch ) )
af.modifier = level / -5;
else
af.modifier = level / -12;
vset( af.bitvector, AFF_CALM );
affect_to_char( vch, &af, NULL );
af.location = APPLY_DAMROLL;
affect_to_char( vch, &af, NULL );
}
}
}
void spell_change_sex( 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 = 10 * level;
af.location = APPLY_SEX;
do
{
af.modifier = number_range( 0, 2 ) - victim->sex;
}
while( af.modifier == 0 );
vset( af.bitvector, AFF_POLYMORPH );
if( !affect_to_char( victim, &af, NULL ) )
return;
if( ch != victim )
send_to_char( "Ok.\n\r", ch );
send_to_char( "You feel different.\n\r", victim );
return;
}
void spell_charge_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int chance;
if( IS_NPC( ch ) )
return;
if( obj->item_type != ITEM_WEAPON )
{
send_to_char( "That item cannot be charged.\n\r", ch );
return;
}
if( obj->wear_loc != WEAR_NONE )
remove_obj( ch, obj->wear_loc, TRUE );
chance = 2 * ( level - obj->level ) + ch->pcdata->learned[sn];
if( IS_OBJ_STAT( obj, ITEM_CHARGED ) )
chance /= 5;
chance = number_range( 1, chance );
if( ch->level >= L_APP || level >= L_APP )
{
chance += 25;
}
if( chance <= 1 )
{
act( "&r$p absorbs too much energy, it explodes in a blinding flash!",
ch, obj, NULL, TO_ALL );
( *skill_table[gsn_explosive].spell_fun )
( gsn_explosive, obj->level, ch, ch );
extract_obj( obj );
return;
}
if( chance < 12 )
{
act( "$p sits there, inert.", ch, obj, NULL, TO_CHAR );
return;
}
SET_BIT( obj->extra_flags, ITEM_CHARGED );
act( "&gA fine web of &Celectricity&g covers $p momentarily.", ch, obj, NULL, TO_CHAR );
act( "&gA fine web of &Celectricity&g covers $p momentarily.", ch, obj, NULL, TO_ROOM );
return;
}
void spell_claim( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
char buf[MAX_INPUT_LENGTH];
if( IS_SET( obj->extra_flags, ITEM_OWNER ) )
{
send_to_char( "You can't claim an item allready claimed.\n\r", ch );
return;
}
SET_BIT( obj->extra_flags, ITEM_OWNER );
sprintf( buf, "%s {%s}", obj->name, ch->name );
free_string( obj->name );
obj->name = str_dup( buf );
act( "$n claims $p for $s own.", ch, obj, NULL, TO_ROOM );
act( "You claim $p for your own.", ch, obj, NULL, TO_CHAR );
return;
}
void spell_cone_of_silence( int sn, int level, CHAR_DATA *ch, void *vo )
{
ROOM_INDEX_DATA *pRoomIndex;
if( !( pRoomIndex = ch->in_room ) )
return;
if( IS_SET( pRoomIndex->room_flags, ROOM_SAFE ) )
{
send_to_char( "You can't do that.\n\r", ch );
return;
}
if( !IS_SET( pRoomIndex->room_flags, ROOM_CONE_OF_SILENCE )
&& !IS_SET( pRoomIndex->room_flags, ROOM_TEMP_CONE_OF_SILENCE ) )
{
SET_BIT( pRoomIndex->room_flags, ROOM_TEMP_CONE_OF_SILENCE );
send_to_char( "You have created a cone of silence!\n\r", ch );
act( "$n has created a cone of silence!", ch, NULL, NULL, TO_ROOM );
create_room_event( pRoomIndex, evn_cone_remove,
level * PULSE_PER_SECOND + 7 * PULSE_TICK );
}
return;
}
void spell_magic_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *light;
light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ), 1 );
obj_to_room( light, ch->in_room );
if( !str_cmp( skill_table[sn].name, "everdark" ) )
{
SET_BIT( light->extra_flags, ITEM_DARK );
REMOVE_BIT( light->extra_flags, ITEM_GLOW );
free_string( light->name );
light->name = str_dup( "ball dark" );
free_string( light->short_descr );
light->short_descr = str_dup( "a ball of utter darkness" );
free_string( light->description );
light->description = str_dup( "The light around this ball of darkness is sucked out of existance.\n\r" );
}
act( "You twiddle your thumbs and $p appears.", ch, light, NULL, TO_CHAR );
act( "$n twiddles $s thumbs and $p appears.", ch, light, NULL, TO_ROOM );
return;
}
void spell_continuous( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *)vo;
char arg[MAX_INPUT_LENGTH];
AFFECT_DATA af;
target_name = one_argument( target_name, arg );
if( target_name[0] == '\0' ||
( af.location = skill_lookup( target_name ) ) <= 0 )
{
send_to_char( "Which spell was that?\n\r", ch );
return;
}
af.type = sn;
af.level = level;
af.modifier = level;
vzero( af.bitvector );
af.duration = 24;
affect_to_char( victim, &af, ch );
if( sn == gsn_continuous_effect )
act( "$n now has continuity.", victim, NULL, NULL, TO_ROOM );
else
act( "$n now has a dread over $s head.", victim, NULL, NULL, TO_ROOM );
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_control_weather( int sn, int level, CHAR_DATA *ch, void *vo )
{
if( !str_cmp( target_name, "better" ) )
ch->in_room->area->plane->weather.change += dice( level / 3, 4 );
else if( !str_cmp( target_name, "worse" ) )
ch->in_room->area->plane->weather.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;
CHAR_DATA *victim;
if( target_name[0] == '\0' )
victim = ch;
else
victim = get_char_room( ch, target_name );
mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ), level );
mushroom->value[0] = 5 + level;
if( victim )
{
obj_to_char( mushroom, victim );
act( "$p suddenly appears on you.", victim, mushroom, NULL, TO_CHAR );
act( "$p suddenly appears on $n.", victim, mushroom, NULL, TO_ROOM );
}
else
{
obj_to_room( mushroom, ch->in_room );
act( "$p suddenly appears.", ch, mushroom, NULL, TO_CHAR );
act( "$p suddenly appears.", ch, mushroom, NULL, TO_ROOM );
}
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 ), 0 );
set_timer_tick( spring, level );
obj_to_room( spring, ch->in_room );
strip_events( &spring->events, evn_imp_grab );
if( !str_cmp( race_table[ch->race].name, "Vampire" ) )
spring->value[2] = LIQ_BLOOD;
act( "$p flows from the ground.", ch, spring, NULL, TO_CHAR );
act( "$p flows from the ground.", ch, spring, NULL, TO_ROOM );
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->value[2] != LIQ_WATER && obj->value[1] != 0 )
{
send_to_char( "It contains some other liquid.\n\r", ch );
return;
}
water = UMIN( level * ( ch->in_room->area->plane->weather.sky >= SKY_RAINING ? 4 : 2 ),
obj->value[0] - obj->value[1] );
if( water > 0 )
{
obj->value[2] = LIQ_WATER;
obj->value[1] += 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_decay( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj;
if( !target_name )
{
send_to_char( "Decay to what?\n\r", ch );
return;
}
obj = get_obj_world( ch, target_name );
if( !obj || ( obj->item_type != ITEM_CORPSE_NPC
&& obj->item_type != ITEM_CORPSE_PC ) )
{
send_to_char( "Sorry that isn't a corpse, you can't do there.\n\r", ch );
return;
}
if( !obj->in_room
|| ch->in_room->area->plane != obj->in_room->area->plane )
{
send_to_char( "You can't find it.\n\r", ch );
return;
}
act( "$n slowly disolves into the ground.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You decay to the corpse.\n\r", ch );
char_from_room( ch );
char_to_room( ch, obj->in_room );
act( "$n rises up from the ground next to $p.", ch, obj, NULL, TO_ROOM );
do_look( ch, AUTOLOOK );
return;
}
void spell_destroy_cursed( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj;
OBJ_DATA *obj_next;
CHAR_DATA *victim = (CHAR_DATA *)vo;
bool yesno = FALSE;
for( obj = victim->carrying; obj; obj = obj_next )
{
obj_next = obj->next_content;
if( IS_SET( obj->extra_flags, ITEM_NODROP )
&& obj->wear_loc == WEAR_NONE )
{
act( "You convulse as you toss $p to the ground, destroying it.",
victim, obj, NULL, TO_CHAR );
act( "$n convulses as $e tosses $p to the ground, destroying it.",
victim, obj, NULL, TO_ROOM );
extract_obj( obj );
yesno = TRUE;
}
}
if( ch != victim && yesno )
send_to_char( "Ok.\n\r", ch );
return;
}
void spell_destroy_life( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch, *vch_next;
act( "$n gestures and you feel the life drain from the room.",
ch, NULL, NULL, TO_ROOM );
for( vch = ch->in_room->people; vch; vch = vch_next )
{
vch_next = vch->next_in_room;
if( !vch->deleted && IS_NPC( vch ) )
{
act( "$n's body crumples to the ground then turns to dust.",
vch, NULL, NULL, TO_ROOM );
extract_char( vch, TRUE );
}
}
return;
}
void spell_dimension_door( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *port;
char buf[MAX_INPUT_LENGTH];
char buf1[MAX_STRING_LENGTH];
ROOM_INDEX_DATA *pRoomIndex;
AREA_DATA *pArea;
PLANE_DATA *pPlane;
int i;
pPlane = plane_lookup( target_name );
for( pArea = area_first; pArea; pArea = pArea->next )
if( !IS_SET( pArea->area_flags, AREA_HIDE ) && pArea->plane == pPlane )
break;
if( !pArea )
{
send_to_char( "That isn't a plane you can shift to.\n\r", ch );
return;
}
if( pArea->plane == ch->in_room->area->plane )
{
send_to_char( "No need to worry, you're allready there.\n\r", ch );
return;
}
for( i = 0; i < 10000; i++ )
{
pRoomIndex = get_room_index( number_range( 0, 65535 ) );
if( pRoomIndex )
if( !IS_SET( pRoomIndex->room_flags, ROOM_PRIVATE )
&& !IS_SET( pRoomIndex->room_flags, ROOM_SOLITARY )
&& !IS_SET( pRoomIndex->room_flags, ROOM_NO_PORTAL )
&& !IS_SET( pRoomIndex->area->area_flags, AREA_HIDE )
&& pRoomIndex->area->plane == pPlane )
break;
}
if( !pRoomIndex )
{
send_to_char( "The warp twists then springs back into place.\n\r", ch );
return;
}
port = create_object( get_obj_index( OBJ_VNUM_DIM_DOOR ), 0 );
set_timer_tick( port, UMIN( level / 10, 20 ) );
port->value[0] = pRoomIndex->vnum;
sprintf( buf, port->description, pArea->plane->name );
port->description = str_dup( buf );
sprintf( buf, port->short_descr, pArea->plane->name );
port->short_descr = str_dup( buf );
obj_to_room( port, ch->in_room );
strip_events( &port->events, evn_imp_grab );
send_to_char( "You summon a gateway formed of pure light.\n\r", ch );
act( "With a bright flash $n creates $p.", ch, port, NULL, TO_ROOM );
sprintf( buf1, "&MINFO: $n has opened a gateway to the %s&M plane of existance.\n", pArea->plane->name );
talk_channel( ch, buf1, CHANNEL_INFO, "INFO" );
port = create_object( get_obj_index( OBJ_VNUM_DIM_DOOR ), 0 );
set_timer_tick( port, UMIN( level / 10, 20 ) );
sprintf( buf, port->description, ch->in_room->area->plane->name );
port->description = str_dup( buf );
sprintf( buf, port->short_descr, ch->in_room->area->plane->name );
port->short_descr = str_dup( buf );
port->value[0] = ch->in_room->vnum;
obj_to_room( port, pRoomIndex );
strip_events( &port->events, evn_imp_grab );
if( pRoomIndex->people )
{
act( "With a blinding flash of light $p appears.",
pRoomIndex->people, port, NULL, TO_CHAR );
act( "With a blinding flash of light $p appears.",
pRoomIndex->people, port, NULL, TO_ROOM );
}
return;
}
/* Dispel Magic recoded by Thelonius for EnvyMud
* Enhanced -- Symp
*/
void spell_dispel_magic( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *)vo;
AFFECT_DATA *paf;
if( victim == ch && str_cmp( target_name, "self" )
&& str_prefix( target_name, ch->name ) )
{
send_to_char( "Are you absolutely certain about this?\n\r", ch );
return;
}
if( !IS_NPC( ch ) && !IS_NPC( victim ) && number_bits( 5 ) == 0
&& ( is_same_group( ch, victim ) || IS_IMMORTAL( ch ) ) )
/* Defensive spell - remove ALL effects */
{
for( paf = victim->affected; paf; paf = paf->next )
{
if( paf->deleted || paf->duration < 0
|| paf->type == gsn_religious
|| paf->type == gsn_racial_fatigue )
continue;
if( xIS_SET( paf->bitvector, AFF_POLYMORPH )
&& get_trust( ch ) < LEVEL_IMMORTAL )
{
send_to_char( "You were unable to remove the Polymorph affect.\n\r",
ch );
continue;
}
if( paf->type == gsn_vampiric_bite
&& get_trust( ch ) < LEVEL_IMMORTAL )
{
send_to_char(
"You were unable to remove the Vampire curse.\n\r",
ch );
continue;
}
affect_remove( victim, paf );
}
if( victim == ch )
{
act( "You have removed all magic effects from yourself.",
ch, NULL, NULL, TO_CHAR );
act( "$n has removed all magic effects from $mself.",
ch, NULL, NULL, TO_ROOM );
}
else
act( "$n has removed all magic effects from $N.",
ch, NULL, victim, TO_ALL );
return;
}
else
/* Offensive spell - enforced by multi_hit whether succeeds or fails */
{
bool removed = FALSE;
if( is_safe( ch, victim ) )
return;
for( paf = victim->affected; paf; paf = paf->next )
{
if( paf->deleted || paf->duration < 0
|| paf->type == gsn_religious
|| paf->type == gsn_racial_fatigue
|| paf->type == gsn_vampiric_bite
|| xIS_SET( paf->bitvector, AFF_POLYMORPH ) )
continue;
if( !saves_dispel( level, paf, victim, ch ) )
{
act( "$n is no longer affected by '$t'.",
victim, skill_table[paf->type].name, NULL, TO_ROOM );
affect_strip( victim, paf->type );
removed = TRUE;
if( number_bits( 1 ) )
break;
}
else
paf->level--;
}
/* ALWAYS give a shot at removing sanctuary */
if( IS_AFFECTED( victim, AFF_SANCTUARY )
&& !saves_spell( level, victim, ch, sn ) )
{
removed = TRUE;
xREMOVE_BIT( victim->affected_by, AFF_SANCTUARY );
send_to_char( "The protective aura around your body fades.\n\r",
victim );
act( "The protective aura around $n's body fades.",
victim, NULL, NULL, TO_ROOM );
}
/* Second pass, reduce time on spells
* Note that the time must be greater than 0 here, this simplifies things.
*/
if( !removed && !saves_spell( level, victim, ch, sn ) )
{
for( paf = victim->affected; paf; paf = paf->next )
{
if( paf->deleted || paf->duration <= 0
|| paf->type == gsn_religious
|| paf->type == gsn_racial_fatigue
|| paf->type == gsn_vampiric_bite
|| xIS_SET( paf->bitvector, AFF_POLYMORPH ) )
continue;
paf->duration--;
paf->level--;
}
send_to_char( "You feel a brief tingling sensation.\n\r", victim );
}
if( !removed )
send_to_char( "You failed to dispel.\n\r", ch );
if( ch != victim && ( !victim->fighting
|| !is_same_group( ch, victim->fighting ) ) )
multi_hit( victim, ch, TYPE_UNDEFINED );
}
return;
}
void spell_enchant_armour( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
AFFECT_DATA *paf;
AFFECT_DATA *paf2;
bool found = FALSE;
int mod = UMIN( 5, ( level + 200 ) / 150 );
int score, normal, number;
if( obj->item_type != ITEM_ARMOUR || IS_NPC( ch ) )
{
send_to_char( "That item cannot be enchanted.\n\r", ch );
return;
}
if( obj->wear_loc != WEAR_NONE )
remove_obj( ch, obj->wear_loc, TRUE );
/*
* Calculate a score based on skill, intelligence, level.
* and a fun bit of randomisation.
*/
score = IS_NPC( ch ) ? 85 : ch->pcdata->learned[sn];
score += get_curr_int( ch );
score += ( 1 - pow( 1.3, obj->level - level ) ) * level / 5;
for( paf = obj->affected; paf; paf = paf->next )
if( !paf->deleted && paf->location == APPLY_AC )
score += paf->modifier;
for( paf = obj->pIndexData->affected; paf; paf = paf->next )
if( !paf->deleted && paf->location == APPLY_AC )
score += paf->modifier;
/*
* Allow extremely unusual results when the character has high wisdom.
*/
number = get_curr_wis( ch ) * 3 / 2;
while( number_bits( 7 ) < number )
score += number_range( -10, 10 );
/*
* Check against the chance...
*/
number = number_bits( 10 );
normal = ench_normal( level, score );
/* tremendously low number, perfect! */
if( number < ench_brilliant( level, score ) )
{
number = 0;
mod += 1;
SET_BIT( obj->extra_flags, ITEM_GLOW );
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p shimmers with a &Ybrilliant &ygold&n aura!", ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &Ybrilliant &ygold&n aura!", ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers with a &Kbrilliant &Kblack&n aura!",
ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &Kbrilliant &Kblack&n aura!",
ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers &Wbrilliantly!&n", ch, obj, NULL, TO_CHAR );
act( "$p shimmers &Wbrilliantly!&n", ch, obj, NULL, TO_ROOM );
}
}
/* reasonable, a normal enchant */
else if( number < normal )
{
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p shimmers with a &ygolden&n aura.",
ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &ygolden&n aura.",
ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers with a &Kblack&n aura.",
ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &Kblack&n aura.",
ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers transparently.", ch, obj, NULL, TO_CHAR );
act( "$p shimmers transparently.", ch, obj, NULL, TO_ROOM );
}
}
/* not quite there */
else if( number < ( 1024 + normal ) / 2 )
{
act( "Nothing seems to happen.", ch, obj, NULL, TO_CHAR );
return;
}
/* oops */
else if( number < UMIN( 1010, ( 1024 * 4 + normal ) / 5 ) )
{
obj->level += 1;
for( paf = obj->affected; paf; paf = paf2 )
{
paf2 = paf->next;
paf->next = affect_free;
affect_free = paf;
}
obj->affected = NULL;
obj->cost = 0;
act( "$p flares &Wbrightly&n then fades ... oh dear!", ch, obj, NULL, TO_CHAR );
act( "$p flares &Wbrightly&n then fades.", ch, obj, NULL, TO_ROOM );
return;
}
else /* uh oh . . . BANG! */
{
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_CHAR );
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_ROOM );
( *skill_table[gsn_explosive].spell_fun )
( gsn_explosive, obj->level, ch, ch );
extract_obj( obj );
return;
}
/*
* Apply affect to item.
*/
SET_BIT( obj->extra_flags, ITEM_MAGIC );
for( paf2 = obj->affected; paf2; paf2 = paf2->next )
{
if( paf2->deleted || paf2->type != sn
|| paf2->location != APPLY_AC || paf2->duration >= 0 )
continue;
paf2->modifier -= 1 + mod;
found = TRUE;
break;
}
if( !found )
{
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_AC;
paf->modifier = -1 - mod;
vzero( paf->bitvector );
paf->next = obj->affected;
obj->affected = paf;
}
if( ch->level < L_APP )
{
if( number == 0 )
obj->level++;
else
obj->level += 1 + mod / 2;
}
return;
}
void spell_enchant_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
AFFECT_DATA *paf;
AFFECT_DATA *paf2;
bool foundhit = FALSE, founddam = FALSE;
int mod = UMIN( 3, ( level + 100 ) / 150 );
int score, normal, number;
if( obj->item_type != ITEM_WEAPON || IS_NPC( ch ) )
{
send_to_char( "That item cannot be enchanted.\n\r", ch );
return;
}
if( obj->wear_loc != WEAR_NONE )
remove_obj( ch, obj->wear_loc, TRUE );
/*
* Calculate a score based on skill, intelligence, level.
* and a fun bit of randomisation.
*/
score = IS_NPC( ch ) ? 85 : ch->pcdata->learned[sn];
score += get_curr_int( ch );
score += ( 1 - pow( 1.3, obj->level - level ) ) * level / 5;
for( paf = obj->affected; paf; paf = paf->next )
if( !paf->deleted && ( paf->location == APPLY_HITROLL
|| paf->location == APPLY_DAMROLL ) )
score -= paf->modifier * 2;
for( paf = obj->pIndexData->affected; paf; paf = paf->next )
if( !paf->deleted && ( paf->location == APPLY_HITROLL
|| paf->location == APPLY_DAMROLL ) )
score -= paf->modifier * 2;
/*
* Allow extremely unusual results when the character has high wisdom.
*/
number = get_curr_wis( ch ) * 3 / 2;
while( number_bits( 7 ) < number )
score += number_range( -10, 10 );
/*
* Check against the chance...
*/
number = number_bits( 10 );
normal = ench_normal( level, score );
/* tremendously low number, perfect! */
if( number < ench_brilliant( level, score ) )
{
number = 0;
mod += 1;
SET_BIT( obj->extra_flags, ITEM_GLOW );
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p glows a &Bbrilliant &bblue&n!", ch, obj, NULL, TO_CHAR );
act( "$p glows a &Bbrilliant &bblue&n!", ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p glows a &Rbrilliant &rred&n!", ch, obj, NULL, TO_CHAR );
act( "$p glows a &Rbrilliant &rred&n!", ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p glows a &Ybrilliant&n &yyellow&n!", ch, obj, NULL, TO_CHAR );
act( "$p glows a &Ybrilliant&n &yyellow&n!", ch, obj, NULL, TO_ROOM );
}
}
/* reasonable, a normal enchant */
else if( number < normal )
{
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p glows &bblue&n.", ch, obj, NULL, TO_CHAR );
act( "$p glows &bblue&n.", ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p glows &rred&n.", ch, obj, NULL, TO_CHAR );
act( "$p glows &rred&n.", ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p glows &yyellow&n.", ch, obj, NULL, TO_CHAR );
act( "$p glows &yyellow&n.", ch, obj, NULL, TO_ROOM );
}
}
/* not quite there */
else if( number < ( 1024 + normal ) / 2 )
{
act( "Nothing seems to happen.", ch, obj, NULL, TO_CHAR );
return;
}
/* oops */
else if( number < UMIN( 1010, ( 1024 * 4 + normal ) / 5 ) )
{
obj->level += 1;
for( paf = obj->affected; paf; paf = paf2 )
{
paf2 = paf->next;
paf->next = affect_free;
affect_free = paf;
}
obj->affected = NULL;
obj->cost = 0;
act( "$p flares &Wbrightly&n then fades ... oh dear!", ch, obj, NULL, TO_CHAR );
act( "$p flares &Wbrightly&n then fades.", ch, obj, NULL, TO_ROOM );
return;
}
else /* uh oh . . . BANG! */
{
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_CHAR );
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_ROOM );
( *skill_table[gsn_explosive].spell_fun )
( gsn_explosive, obj->level, ch, ch );
extract_obj( obj );
return;
}
/*
* Apply affect to item.
*/
SET_BIT( obj->extra_flags, ITEM_MAGIC );
for( paf2 = obj->affected; paf2; paf2 = paf2->next )
{
if( paf2->deleted || paf2->type != sn
|| paf2->location != APPLY_HITROLL || paf2->duration >= 0 )
continue;
paf2->modifier += 1 + mod;
foundhit = TRUE;
break;
}
for( paf2 = obj->affected; paf2; paf2 = paf2->next )
{
if( paf2->deleted || paf2->type != sn
|| paf2->location != APPLY_DAMROLL || paf2->duration >= 0 )
continue;
paf2->modifier += 1 + mod;
founddam = TRUE;
break;
}
if( !foundhit )
{
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_HITROLL;
paf->modifier = 1 + mod;
vzero( paf->bitvector );
paf->next = obj->affected;
obj->affected = paf;
}
if( !founddam )
{
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_DAMROLL;
paf->modifier = 1 + mod;
vzero( paf->bitvector );
paf->next = obj->affected;
obj->affected = paf;
}
if( ch->level < L_APP )
{
if( number == 0 )
obj->level++;
else
obj->level += 1 + mod / 2;
}
return;
}
void spell_enhance_armour( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
AFFECT_DATA *paf;
AFFECT_DATA *paf2;
int mod = UMIN( 3, ( level + 100 ) / 150 ) * 3;
bool found = FALSE;
int score, normal, number;
if( obj->item_type != ITEM_ARMOUR
|| IS_SET( obj->extra_flags, ITEM_MAGIC ) )
{
send_to_char( "That item cannot be enhanced.\n\r", ch );
return;
}
if( obj->wear_loc != WEAR_NONE )
remove_obj( ch, obj->wear_loc, TRUE );
/*
* Calculate a score based on skill, intelligence, level.
* and a fun bit of randomisation.
*/
score = IS_NPC( ch ) ? 85 : ch->pcdata->learned[sn];
score += get_curr_int( ch );
score += ( 1 - pow( 1.3, obj->level - level ) ) * level / 5;
for( paf = obj->affected; paf; paf = paf->next )
if( !paf->deleted && paf->location == APPLY_RESILIENCE )
score += paf->modifier * 2;
for( paf = obj->pIndexData->affected; paf; paf = paf->next )
if( !paf->deleted && paf->location == APPLY_RESILIENCE )
score += paf->modifier * 2;
/*
* Allow extremely unusual results when the character has high wisdom.
*/
number = get_curr_wis( ch ) * 3 / 2;
while( number_bits( 7 ) < number )
score += number_range( -10, 10 );
/*
* Check against the chance...
*/
number = number_bits( 10 );
normal = ench_normal( level, score );
/* tremendously low number, perfect! */
if( number < ench_brilliant( level, score ) )
{
number = 0;
mod += 3;
SET_BIT( obj->extra_flags, ITEM_GLOW );
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p shimmers with a &Ybrilliant &ygold&n aura!",
ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &Ybrilliant &ygold&n aura!",
ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers with a &K&7brilliant &kblack&n aura!",
ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &K&7brilliant &kblack&n aura!",
ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shines &Wbrilliantly!&n", ch, obj, NULL, TO_CHAR );
act( "$p shines &Wbrilliantly!&n", ch, obj, NULL, TO_ROOM );
}
}
/* reasonable, a normal enchant */
else if( number < normal )
{
if( IS_GOOD( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
act( "$p shimmers with a &ygolden&n aura.", ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &ygolden&n aura.", ch, obj, NULL, TO_ROOM );
}
else if( IS_EVIL( ch ) )
{
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers with a &k&7black&n aura.", ch, obj, NULL, TO_CHAR );
act( "$p shimmers with a &k&7black&n aura.", ch, obj, NULL, TO_ROOM );
}
else
{
SET_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
SET_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
act( "$p shimmers transparently.", ch, obj, NULL, TO_CHAR );
act( "$p shimmers transparently.", ch, obj, NULL, TO_ROOM );
}
}
/* not quite there */
else if( number < ( 1024 + normal ) / 2 )
{
act( "Nothing seems to happen.", ch, obj, NULL, TO_CHAR );
return;
}
/* oops */
else if( number < UMIN( 1010, ( 1024 * 4 + normal ) / 5 ) )
{
obj->level += 1;
for( paf = obj->affected; paf; paf = paf2 )
{
paf2 = paf->next;
paf->next = affect_free;
affect_free = paf;
}
obj->affected = NULL;
obj->cost = 0;
act( "$p flares &Wbrightly&n then fades ... oh dear!", ch, obj, NULL, TO_CHAR );
act( "$p flares &Wbrightly&n then fades.", ch, obj, NULL, TO_ROOM );
return;
}
else /* uh oh . . . BANG! */
{
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_CHAR );
act( "$p shudders violently and then explodes!", ch, obj, NULL, TO_ROOM );
( *skill_table[gsn_explosive].spell_fun )
( gsn_explosive, obj->level, ch, ch );
extract_obj( obj );
return;
}
/*
* Apply affect to item.
*/
SET_BIT( obj->extra_flags, ITEM_MAGIC );
for( paf2 = obj->affected; paf2; paf2 = paf2->next )
{
if( paf2->deleted || paf2->type != sn
|| paf2->location != APPLY_RESILIENCE || paf2->duration >= 0 )
continue;
paf2->modifier -= 5 + mod;
found = TRUE;
break;
}
if( !found )
{
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_RESILIENCE;
paf->modifier = -5 - mod;
vzero( paf->bitvector );
paf->next = obj->affected;
obj->affected = paf;
}
if( ch->level < L_APP )
{
if( number == 0 )
obj->level++;
else
obj->level += 1 + mod / 2;
}
return;
}
void spell_flame_of_god( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int chance;
if( IS_NPC( ch ) )
return;
if( obj->item_type != ITEM_WEAPON )
{
send_to_char( "That isn't a weapon.\n\r", ch );
return;
}
chance = level - obj->level + ( ch->pcdata->learned[sn] / 2 );
chance -= number_percent( );
if( chance < -50 )
{
send_to_char( "You anger your god and he destroys the weapon.\n\r", ch );
extract_obj( obj );
return;
}
if( chance < 0 )
{
send_to_char( "Nothing much happens.\n\r", ch );
return;
}
obj->value[0] = skill_lookup( "flamestrike" );
SET_BIT( obj->extra_flags, ITEM_HOLY );
act( "You summon your god and $p burns with holy fire!", ch, obj, NULL, TO_CHAR );
act( "$n summons $s god and $p burns with holy fire!", ch, obj, NULL, TO_ROOM );
return;
}
/*
* Disgusting recursion to flood properly.
*/
void flood_room( ROOM_INDEX_DATA *room )
{
ROOM_INDEX_DATA *toroom;
int i;
if( IS_SET( room->room_flags, ROOM_SAFE )
|| room->sector_type == SECT_DESERT )
{
send_to_room( "Some water laps at your feet.", room );
return;
}
if( room->sector_type == SECT_WATER_NOSWIM
|| room->sector_type == SECT_WATER_SWIM
|| room->sector_type == SECT_UNDERWATER )
{
send_to_room( "A small wave stirs the water.", room );
return;
}
SET_BIT( room->room_flags, ROOM_FLOODED );
for( i = 0; i < MAX_DIR; ++i )
{
if( !room->exit[i] || !( toroom = room->exit[i]->to_room )
|| IS_SET( toroom->room_flags, ROOM_FLOODED ) )
continue;
if( i == DIR_UP || ( toroom->area != room->area )
|| ( room->sector_type == SECT_AIR && i != DIR_DOWN ) )
{
send_to_room( "Some water laps at your feet.", toroom );
continue;
}
flood_room( toroom );
}
return;
}
void spell_flood( int sn, int level, CHAR_DATA *ch, void *vo )
{
if( ch->in_room->sector_type == SECT_SPACE )
{
act( "$n summon$% a flood of water that instantly turns to vapour.",
ch, NULL, NULL, TO_ALL );
return;
}
if( ch->in_room->sector_type == SECT_UNDERWATER )
{
act( "$n tries to summon a flood but the water only shimmers.",
ch, NULL, NULL, TO_ROOM );
act( "You find the weight of water blocks the spell.",
ch, NULL, NULL, TO_CHAR );
return;
}
if( IS_SET( ch->in_room->area->area_flags, AREA_NO_FLOOD ) )
{
act( "$n tries to summons a flood but the water simply drains away.",
ch, NULL, NULL, TO_ROOM );
act( "You try to summon a flood but the water simply drains away.",
ch, NULL, NULL, TO_CHAR );
return;
}
act( "$n touches the ground and water gushes up, flooding the room.",
ch, NULL, NULL, TO_ROOM );
send_to_char(
"You touch the ground and raise water to flood everything.\n\r", ch );
flood_room( ch->in_room );
return;
}
void spell_gate( int sn, int level, CHAR_DATA *ch, void *vo )
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *gch, *mob;
int npccount = 0;
int pccount = 0;
for( gch = ch->in_room->people; gch; gch = gch->next_in_room )
{
if( IS_NPC( gch ) && !IS_AFFECTED( gch, AFF_CHARM ) )
npccount++;
if( !IS_NPC( gch ) ||
( IS_NPC( gch ) && IS_AFFECTED( gch, AFF_CHARM ) ) )
pccount++;
}
if( IS_NPC( ch ) && npccount > pccount )
{
do_say( ch, "There are too many of us here! One must die!" );
return;
}
do_say( ch, "Come brothers! Join me in this glorious bloodbath!" );
pMob = get_mob_index( MOB_VNUM_DEMON );
pMob->level = number_fuzzy( level ) - 1;
mob = create_mobile( pMob );
pMob->level = 10;
mob->master = ch;
mob->gold = 0;
create_char_event( mob, evn_gate_demon,
percent_fuzzy( level * 15 + 300, 12 )
* PULSE_PER_SECOND );
if( !IS_NPC( ch ) )
xSET_BIT( mob->affected_by, AFF_CHARM );
if( number_percent( ) < ch->level )
xSET_BIT( mob->affected_by, AFF_SANCTUARY );
if( number_percent( ) < ch->level )
xSET_BIT( mob->affected_by, AFF_FLYING );
if( !IS_NPC( ch ) && number_percent( ) > ch->pcdata->learned[sn] )
xSET_BIT( mob->act, ACT_WIMPY );
if( ch->fighting )
{
mob->position = POS_FIGHTING;
mob->fighting = ch->fighting;
}
char_to_room( mob, ch->in_room );
return;
}
void spell_gift_item( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
CHAR_DATA *victim;
char buf[MAX_INPUT_LENGTH];
char *p;
/* Who to gift it to */
target_name = one_argument( target_name, buf );
victim = get_char_world( ch, target_name );
if( !victim || IS_NPC( victim ) )
{
send_to_char( "You cant find that person.\n\r", ch );
return;
}
if( victim == ch )
{
send_to_char( "HAH! that was certainly worth the mana!\n\r", ch );
return;
}
/* Do they own it? */
if( !is_owner( ch, obj ) )
{
send_to_char( "You don't own that particular item.\n\r", ch );
send_to_char( "Hence you cannot make a gift of it.\n\r", ch );
return;
}
/* Remove owner flag */
sprintf( buf, " {%s}", ch->name );
for( p = obj->name; *p != '\0'; ++p )
{
if( *p == ' ' && !str_prefix( buf, p ) )
{
strcpy( buf, obj->name );
buf[p - obj->name] = '\0';
free_string( obj->name );
obj->name = str_dup( buf );
break;
}
}
/* add new owner flag */
sprintf( buf, "%s {%s}", obj->name, victim->name );
free_string( obj->name );
obj->name = str_dup( buf );
act( "$N has gifted you with $p.", victim, obj, ch, TO_CHAR );
act( "$n has gifted $p to $N.", ch, obj, victim, TO_NOTVICT );
act( "You gift $p to $N.", ch, obj, victim, TO_CHAR );
return;
}
void spell_glitterdust( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *ich;
send_to_char( "You conjure a cloud of sparkling particles.\n\r", ch );
act( "$n conjures a cloud of sparkling particles.",
ch, NULL, NULL, TO_ROOM );
for( ich = ch->in_room->people; ich; ich = ich->next_in_room )
{
if( !IS_NPC( ich ) && xIS_SET( ich->act, PLR_WIZINVIS ) )
continue;
if( ich == ch || saves_spell( level, ich, ch, sn ) )
continue;
affect_strip( ich, gsn_invis );
affect_strip( ich, gsn_mass_invis );
affect_strip( ich, gsn_vanish );
affect_strip( ich, gsn_sneak );
affect_strip( ich, gsn_move_hidden );
xREMOVE_BIT( ich->affected_by, AFF_HIDE );
xREMOVE_BIT( ich->affected_by, AFF_INVISIBLE );
xREMOVE_BIT( ich->affected_by, AFF_SNEAK );
act( "$n is covered in sparkles!", ich, NULL, NULL, TO_ROOM );
send_to_char( "You are revealed!\n\r", ich );
}
return;
}
/* Remove Alignment by Thelonius for EnvyMud */
void spell_harmonise( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
if( !IS_SET( obj->extra_flags, ITEM_EVIL )
&& !IS_SET( obj->extra_flags, ITEM_ANTI_GOOD )
&& !IS_SET( obj->extra_flags, ITEM_ANTI_EVIL )
&& !IS_SET( obj->extra_flags, ITEM_ANTI_NEUTRAL ) )
{
send_to_char( "Nothing happens.\n\r", ch );
return;
}
if( !IS_NPC( ch ) && number_percent( ) < ch->pcdata->learned[sn] *
( 33 +
( 33 * ( ch->level - obj->level ) / (float)LEVEL_HERO ) ) / 100.0 )
{
REMOVE_BIT( obj->extra_flags, ITEM_EVIL );
REMOVE_BIT( obj->extra_flags, ITEM_ANTI_GOOD );
REMOVE_BIT( obj->extra_flags, ITEM_ANTI_EVIL );
REMOVE_BIT( obj->extra_flags, ITEM_ANTI_NEUTRAL );
act( "$p hums briefly, then lies quiet.", ch, obj, NULL, TO_CHAR );
act( "$p hums briefly, then lies quiet.", ch, obj, NULL, TO_ROOM );
return;
}
SET_BIT( obj->extra_flags, ITEM_NODROP );
obj->wear_flags = ITEM_TAKE; /* Useless */
obj->cost = 0; /* Worthless */
act( "$p blazes brightly, then turns grey.", ch, obj, NULL, TO_CHAR );
act( "$p blazes brightly, then turns grey.", ch, obj, NULL, TO_ROOM );
return;
}
void spell_holy_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int flags = ITEM_HOLY;
if( obj->level - 5 > level )
{
send_to_char( "Alas, you can do nothing for this item.\n\r", ch );
return;
}
if( IS_SET( obj->extra_flags, ITEM_RUNED ) )
SET_BIT( flags, ITEM_RUNED );
if( IS_SET( obj->extra_flags, ITEM_OWNER ) )
SET_BIT( flags, ITEM_OWNER );
obj->extra_flags = flags;
act( "$p flares with power as $n's god answers $s call.", ch, obj, NULL, TO_ROOM );
act( "$p flares with power as god answers your call.", ch, obj, NULL, TO_CHAR );
return;
}
void spell_ice_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int chance;
if( IS_NPC( ch ) )
return;
if( obj->item_type != ITEM_WEAPON )
{
send_to_char( "That isn't a weapon.\n\r", ch );
return;
}
chance = level - obj->level + ( ch->pcdata->learned[sn] / 2 );
chance -= number_percent( );
if( chance < -50 )
{
send_to_char( "You fumble and the weapon shatters.\n\r", ch );
extract_obj( obj );
return;
}
if( chance < 0 )
{
send_to_char( "Nothing much happens.\n\r", ch );
return;
}
obj->value[0] = skill_lookup( "freeze" );
SET_BIT( obj->extra_flags, ITEM_GLOW );
act( "You draw the heat from $p and coat it with magical ice!",
ch, obj, NULL, TO_CHAR );
act( "$n draws the heat from $p and covers it in magical ice!",
ch, obj, NULL, TO_ROOM );
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_INPUT_LENGTH];
if( IS_SET( obj->extra_flags, ITEM_NO_IDENTIFY )
|| number_bits( 5 ) > get_curr_int( ch ) )
{
send_to_char( "You don't seem to gain any insights.\n\r", ch );
return;
}
charprintf( ch, "Object '%s' is type %s.\n\r",
obj->name, flag_string( type_flags, &obj->item_type ) );
charprintf( ch, "Extra flags: %s.\n\r",
flag_string( extra_flags, &obj->extra_flags ) );
charprintf( ch, "Weight is %d, value is %d, level is %d.\n\r",
obj->weight, obj->cost, obj->level );
if( obj->required_skill > 0 )
charprintf( ch, "Requires skill: %s\n\r",
skill_table[obj->required_skill].name );
charprintf( ch, "This item mainly consists of: %s\n\r",
flag_string( material_flags, &obj->pIndexData->material ) );
charprintf( ch, "Item condition is about %d%%\n\r",
number_fuzzy( obj->condition / 10 ) );
switch( obj->item_type )
{
case ITEM_CONTAINER:
if( IS_SET( obj->value[1], CONT_WEIGHTLESS ) )
send_to_char( "Container is a bag of holding.\n\r", ch );
break;
case ITEM_EXPLOSIVE:
charprintf( ch, "Explodes at a level of %d.\n\r", obj->value[0] );
break;
case ITEM_PILL:
case ITEM_SCROLL:
case ITEM_POTION:
charprintf( ch, "Level %d spells of:", obj->value[0] );
if( obj->value[1] >= 0 && obj->value[1] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->value[1]].name, ch );
send_to_char( "'", ch );
}
if( obj->value[2] >= 0 && obj->value[2] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->value[2]].name, ch );
send_to_char( "'", ch );
}
if( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
{
send_to_char( " '", ch );
send_to_char( skill_table[obj->value[3]].name, ch );
send_to_char( "'", ch );
}
send_to_char( ".\n\r", ch );
break;
case ITEM_WAND:
case ITEM_STAFF:
charprintf( ch, "Has %d(%d) charges of level %d",
obj->value[1], obj->value[2], obj->value[0] );
if( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
charprintf( ch, " '%s'", skill_table[obj->value[3]].name );
send_to_char( ".\n\r", ch );
break;
case ITEM_WEAPON:
charprintf( ch, "Damage is %d to %d (average %d).\n\r",
obj->value[1], obj->value[2],
( obj->value[1] + obj->value[2] ) / 2 );
if( obj->value[0] > 0 )
charprintf( ch, "Casts spell, %s, with every hit.\n\r",
skill_table[obj->value[0]].name );
break;
case ITEM_ARMOUR:
charprintf( ch, "Armour class is %d.\n\r", obj->value[0] );
if( obj->value[1] < 0 )
send_to_char( "A tag says 'one size fits all'.\n\r", ch );
else
charprintf( ch, "A tag says that this is size %d.\n\r", obj->value[1] );
break;
case ITEM_CORPSE_NPC:
charprintf( ch, "Corpse is of the %s race.\n\r",
race_table[URANGE( 0, obj->value[0], MAX_RACE - 1 )].name );
break;
case ITEM_TREASURE:
charprintf( ch, "Treasure should be saleable for about %s.\n\r",
int_to_str_special( obj->value[0] ) );
break;
case ITEM_BOOK:
charprintf( ch, "Book teaches the skill/spell '%s'.\n\r",
skill_table[obj->value[0]].name );
break;
}
for( paf = obj->pIndexData->affected; paf; paf = paf->next )
send_to_char( show_affect( buf, paf, TRUE, FALSE ), ch );
for( paf = obj->affected; paf; paf = paf->next )
send_to_char( show_affect( buf, paf, TRUE, FALSE ), ch );
return;
}
void spell_incite_brawl( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *mch;
CHAR_DATA *vch;
CHAR_DATA *victim = NULL;
int count;
if( IS_NPC( ch ) )
return;
send_to_char( "You encourage the tension in the room to grow.\n\r", ch );
act( "$n encourages the tension in the room with subtle words.",
ch, NULL, NULL, TO_ROOM );
/* basically aggr_update( ) reconstructed with a lot of the checks
thrown out so a free-for-all ensues, also added chance
if the mob saves vs spell that they will attack the caster
but normally the caster is left well alone.
Symposium */
for( mch = ch->in_room->people; mch; mch = mch->next_in_room )
{
if( !IS_NPC( mch )
|| mch->deleted
|| mch->fighting
|| IS_AFFECTED( mch, AFF_CHARM )
|| !IS_AWAKE( mch ) )
continue;
if( saves_spell( level, mch, ch, sn ) && number_bits( 2 ) == 0 )
{
act( "$n recognises $N's deceit.", mch, NULL, ch, TO_ROOM );
act( "$n screams and attacks $N.", mch, NULL, ch, TO_NOTVICT );
act( "$n screams and attacks you.", mch, NULL, ch, TO_VICT );
multi_hit( mch, ch, TYPE_UNDEFINED );
continue;
}
count = 0;
for( vch = mch->in_room->people; vch; vch = vch->next_in_room )
{
if( vch->deleted || vch == ch
|| vch->level >= LEVEL_IMMORTAL )
continue;
if( can_see( mch, vch ) && mch != vch )
{
if( number_range( 0, count ) == 0 )
victim = vch;
count++;
}
}
if( !victim || victim == ch )
continue;
act( "$n screams and attacks $N.", mch, NULL, victim, TO_NOTVICT );
act( "$n screams and attacks you.", mch, NULL, victim, TO_VICT );
multi_hit( mch, victim, TYPE_UNDEFINED );
}
return;
}
void spell_know_alignment( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *)vo;
const 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_locate_object( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj;
OBJ_DATA *in_obj;
char buf1[ MAX_STRING_LENGTH * 2 ];
char buf[MAX_INPUT_LENGTH];
char arg[MAX_INPUT_LENGTH];
int found = 0;
int num;
buf1[0] = '\0';
num = number_argument( target_name, arg );
for( obj = object_list; found < 74 + num && obj; obj = obj->next )
{
if( !can_see_obj( ch, obj ) || !is_obj_name( obj, arg ) )
continue;
if( ++found < num )
continue;
for( in_obj = obj; in_obj->in_obj; in_obj = in_obj->in_obj )
;
if( in_obj->carried_by )
{
sprintf( buf, "%s&n carried by %s&n.\n\r",
obj->short_descr, PERS( in_obj->carried_by, ch ) );
}
else
{
sprintf( buf, "%s&n in %s&n.\n\r",
obj->short_descr, !in_obj->in_room
? "somewhere" : in_obj->in_room->name );
}
buf[0] = UPPER( buf[0] );
strcat( buf1, buf );
}
if( !found )
strcat( buf1, "Nothing like that in hell, earth, or heaven.\n\r" );
else if( found >= 74 + num )
strcat( buf1, "--Limit of 75 objects reached--\n\r" );
else if( found < num )
strcat( buf1, "No objects found in that range.\n\r" );
send_to_char( buf1, ch );
return;
}
void spell_mercy( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *cor;
char buf[MAX_INPUT_LENGTH];
if( IS_NPC( ch ) )
return;
sprintf( buf, "corpse %s", ch->name );
for( cor = object_list; cor; cor = cor->next )
if( !cor->deleted && cor->item_type == ITEM_CORPSE_PC
&& !str_cmp( cor->name, buf ) )
break;
if( !cor || !cor->in_room
|| ch->in_room->area->plane != cor->in_room->area->plane )
{
send_to_char( "You can't find it.\n\r", ch );
return;
}
act( "$n disappears to retrieve $s corpse.", ch, NULL, NULL, TO_ROOM );
char_from_room( ch );
char_to_room( ch, cor->in_room );
act( "$n appears in a flash next to $s corpse.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You appear beside your corpse.\n\r", ch );
do_look( ch, AUTOLOOK );
return;
}
void spell_nexus( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *port;
CHAR_DATA *rch;
ROOM_INDEX_DATA *location;
char buf[MAX_INPUT_LENGTH];
rch = get_char_world( ch, target_name );
if( !rch || !( location = rch->in_room )
|| IS_SET( location->room_flags, ROOM_NO_PORTAL )
|| level + 50 < rch->level
|| level + 50 < location->area->min
|| IS_SET( location->area->area_flags, AREA_HIDE )
|| ch->in_room->area->plane != location->area->plane )
{
send_to_char( "You grope about but there is nothing there.\n\r", ch );
return;
}
port = create_object( get_obj_index( OBJ_VNUM_NEXUS ), 0 );
set_timer_tick( port, UMIN( level / 6, 25 ) );
port->value[0] = location->vnum;
sprintf( buf, port->description, location->name );
port->description = str_dup( buf );
sprintf( buf, port->short_descr, location->name );
port->short_descr = str_dup( buf );
obj_to_room( port, ch->in_room );
strip_events( &port->events, evn_imp_grab );
send_to_char( "You force a hole in the firmament.\n\r", ch );
act( "$n firmly tears the firmament and a gateway appears.",
ch, port, NULL, TO_ROOM );
port = create_object( get_obj_index( OBJ_VNUM_NEXUS ), 0 );
set_timer_tick( port, UMIN( level / 6, 25 ) );
sprintf( buf, port->description, ch->in_room->name );
port->description = str_dup( buf );
sprintf( buf, port->short_descr, ch->in_room->name );
port->short_descr = str_dup( buf );
port->value[0] = ch->in_room->vnum;
obj_to_room( port, location );
strip_events( &port->events, evn_imp_grab );
send_to_char( "You feel a strange pulling sensation.\n\r", rch );
act( "Reality tears in two and a gateway appears.",
rch, port, NULL, TO_ROOM );
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_planeshift( int sn, int level, CHAR_DATA *ch, void *vo )
{
ROOM_INDEX_DATA *pRoomIndex;
char buf[MAX_STRING_LENGTH];
AREA_DATA *pArea;
PLANE_DATA *pPlane;
int i;
pPlane = plane_lookup( target_name );
for( pArea = area_first; pArea; pArea = pArea->next )
if( !IS_SET( pArea->area_flags, AREA_HIDE ) && pArea->plane == pPlane )
break;
if( !pArea )
{
send_to_char( "That isn't a plane you can shift to.\n\r", ch );
return;
}
if( pArea->plane == ch->in_room->area->plane )
{
send_to_char( "No need to worry, you're allready there.\n\r", ch );
return;
}
for( i = 0; i < 10000; i++ )
{
pRoomIndex = get_room_index( number_range( 0, 65535 ) );
if( pRoomIndex )
if( !IS_SET( pRoomIndex->room_flags, ROOM_PRIVATE )
&& !IS_SET( pRoomIndex->room_flags, ROOM_SOLITARY )
&& !IS_SET( pRoomIndex->room_flags, ROOM_NO_PORTAL )
&& !IS_SET( pRoomIndex->area->area_flags, AREA_HIDE )
&& pRoomIndex->area->plane == pPlane )
break;
}
if( !pRoomIndex )
{
send_to_char( "The warp twists then springs back into place.\n\r", ch );
return;
}
act( "&g$n disappears in a bright green flash!", ch, NULL, NULL, TO_ROOM );
char_from_room( ch );
char_to_room( ch, pRoomIndex );
act( "&g$n suddenly appears through a flash of bright light!",
ch, NULL, NULL, TO_ROOM );
sprintf( buf, "&MINFO: $n has shifted to the %s&M plane of existance.\n",
pArea->plane->name );
talk_channel( ch, buf, CHANNEL_INFO, "INFO" );
do_look( ch, AUTOLOOK );
return;
}
void spell_polymorph_other( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *)vo;
AFFECT_DATA af;
char buf[MAX_STRING_LENGTH];
if( IS_AFFECTED( victim, AFF_POLYMORPH ) )
{
act( "$E is already changed.", ch, NULL, victim, TO_CHAR );
return;
}
af.type = sn;
af.level = level;
af.duration = dice( 10, level );
af.location = APPLY_RACE;
do
{
af.modifier = number_range( 0, MAX_RACE - 1 ) - victim->race;
}
while( af.modifier == 0 );
vset( af.bitvector, AFF_POLYMORPH );
affect_to_char( victim, &af, NULL );
if( ch != victim )
send_to_char( "Ok.\n\r", ch );
send_to_char( "You feel different.\n\r", victim );
if( !IS_NPC( ch ) || get_trust( ch ) > LEVEL_HERO )
{
sprintf( buf, "Log %s: casting Polymorph other", ch->name );
log_string( buf );
}
}
void spell_portal( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *port;
CHAR_DATA *rch;
ROOM_INDEX_DATA *location;
char buf[MAX_INPUT_LENGTH];
if( target_name[0] == '\0' )
{
send_to_char( "Where to?\n\r", ch );
return;
}
rch = get_char_world( ch, target_name );
if( !rch || !( location = rch->in_room )
|| IS_SET( location->room_flags, ROOM_NO_PORTAL )
|| level + 50 < rch->level
|| level + 50 < location->area->min
|| IS_SET( location->area->area_flags, AREA_HIDE )
|| ch->in_room->area->plane != location->area->plane )
{
send_to_char( "Your spell splutters and dies.\n\r", ch );
return;
}
port = create_object( get_obj_index( OBJ_VNUM_PORTAL ), 0 );
set_timer_tick( port, level / 12 );
port->value[0] = location->vnum;
sprintf( buf, port->description, location->name );
free_string( port->description );
port->description = str_dup( buf );
sprintf( buf, port->short_descr, location->name );
free_string( port->short_descr );
port->short_descr = str_dup( buf );
obj_to_room( port, ch->in_room );
strip_events( &port->events, evn_imp_grab );
act( "You make $p turn sideways and appear.", ch, port, NULL, TO_CHAR );
act( "$n makes $p turn sideways and appear.", ch, port, NULL, TO_ROOM );
return;
}
void spell_recharge_item( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int restore, score;
if( obj->item_type != ITEM_GEM && obj->item_type != ITEM_WAND
&& obj->item_type != ITEM_STAFF )
{
send_to_char( "That item cannot be recharged.\n\r", ch );
return;
}
restore = obj->value[1] - obj->value[2];
if( obj->item_type == ITEM_GEM )
restore = UMIN( restore, ch->mana[obj->value[0]] );
/* chance of restoring less than full */
restore = UMIN( restore, number_range( 0, restore * 3 / 2 ) );
if( obj->item_type == ITEM_GEM )
score = 3 * ( ch->level - obj->level );
else
score = 3 * ( ch->level - obj->value[0] );
score += ch->pcdata->learned[sn] / 2;
if( number_percent( ) < score && restore > 0 )
{
obj->value[2] += restore;
obj->value[1] = obj->value[2];
obj->level++;
obj->cost = 1;
act( "$p shines brightly, then returns to normal.",
ch, obj, NULL, TO_CHAR );
act( "$p shines brightly, then returns to normal.",
ch, obj, NULL, TO_ROOM );
}
else
{
act( "$p shines brightly, then explodes into fragments!",
ch, obj, NULL, TO_CHAR );
act( "$p shines brightly, then explodes into fragments!",
ch, obj, NULL, TO_ROOM );
extract_obj( obj );
damage( ch, ch, ch->max_hit / 16, sn, WEAR_NONE );
}
return;
}
void spell_glamour( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
char arg[MAX_INPUT_LENGTH];
target_name = one_argument( target_name, arg );
if( target_name[0] == '\0' )
{
send_to_char( "You must specify a name for the item.\n\r", ch );
return;
}
act( "$n change$% $t into $T with a flick of $s wrist.",
ch, obj->short_descr, target_name, TO_ALL );
free_string( obj->short_descr );
obj->short_descr = str_dup( target_name );
return;
}
void spell_resurrect( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim;
OBJ_DATA *corpse;
char buf[MAX_INPUT_LENGTH];
char name[MAX_INPUT_LENGTH];
bool found = FALSE;
int xp = 0;
victim = get_char_world( ch, target_name );
if( !victim || IS_NPC( victim ) )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( !ch->in_room || !victim->in_room
|| ch->in_room->area->plane != victim->in_room->area->plane )
{
send_to_char( "You can't help them.\n\r", ch );
return;
}
if( victim->fighting || ( victim->level >= level + 3
&& ch->class != CLASS_ANGEL ) )
{
send_to_char( "You can't summon that person.\n\r", ch );
return;
}
sprintf( name, "corpse %s", victim->name );
for( corpse = object_list; corpse; corpse = corpse->next )
{
if( corpse->deleted )
continue;
if( corpse->item_type == ITEM_CORPSE_PC && !str_cmp( name, corpse->name )
&& corpse->in_room != ch->in_room )
{
found = TRUE;
sprintf( buf, "%s disappears suddenly.", corpse->short_descr );
send_to_room( buf, corpse->in_room );
obj_from_room( corpse );
obj_to_room( corpse, ch->in_room );
strip_events( &corpse->events, evn_imp_grab );
act( "$p appears right in front of you.\n\r",
victim, corpse, NULL, TO_CHAR );
xp += number_range( 4000, 10000 );
}
}
if( !found )
{
send_to_char( "That person has no corpse, you can't help them.\n\r", ch );
return;
}
if( victim->in_room != ch->in_room )
{
if( victim->in_room )
{
act( "$n disappears suddenly, summoned by $N.",
victim, NULL, ch, TO_ROOM );
char_from_room( victim );
}
char_to_room( victim, ch->in_room );
act( "You help $N.", ch, NULL, victim, TO_CHAR );
act( "$n has decided to help you.", ch, NULL, victim, TO_VICT );
act( "$N materialises at $n's intervention.",
ch, NULL, victim, TO_NOTVICT );
do_look( victim, AUTOLOOK );
}
if( ch->class == CLASS_ANGEL )
{
send_to_char( "You feel renewed by the good deed.\n\r", ch );
gain_exp( ch, xp );
}
sprintf( buf, "%s has shown mercy and resurrected %s.",
ch->name, victim->name );
talk_channel( NULL, buf, CHANNEL_INFO, "INFO" );
return;
}
void spell_scry( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *rch;
ROOM_INDEX_DATA *location, *oldloc;
if( target_name[0] == '\0' )
{
send_to_char( "Where did you want to go?\n\r", ch );
return;
}
rch = get_char_world( ch, target_name );
if( !rch || !( location = rch->in_room ) )
{
send_to_char( "Your spell fizzles.\n\r", ch );
return;
}
if( room_is_private( location )
|| IS_SET( location->room_flags, ROOM_NO_PORTAL )
|| location->area->min > level + 50
|| IS_SET( location->area->area_flags, AREA_HIDE )
|| ch->in_room->area->plane != location->area->plane )
{
send_to_char( "You see &vmilky grey&n.\n\r", ch );
return;
}
oldloc = ch->in_room;
char_from_room( ch );
char_to_room( ch, location );
do_look( ch, AUTOLOOK );
char_from_room( ch );
char_to_room( ch, oldloc );
return;
}
void spell_shadow_door( int sn, int level, CHAR_DATA *ch, void *vo )
{
ROOM_INDEX_DATA *location;
char target[MAX_INPUT_LENGTH];
char *dir;
const char *directions = "neswud";
bool destok = FALSE;
one_argument( target_name, target ); /* remove trailing space */
if( target[0] == '\0' )
{
send_to_char( "Where did you want to go?\n\r", ch );
return;
}
if( (int)strlen( target ) > ch->level / 50 )
{
send_to_char( "If you attempted that distance you would surely perish!\n\r", ch );
return;
}
for( dir = target; dir && *dir; dir++ )
{
char *d = strchr( directions, LOWER( *dir ) );
if( !d )
{
send_to_char( "You must specify directions to travel.\n\r", ch );
return;
}
}
act( "&K$n step$% into the shadows and disappear$%.",
ch, NULL, NULL, TO_ALL );
do
{
location = ch->in_room;
for( dir = target; dir && *dir; dir++ )
{
int door;
switch( LOWER( *dir ) )
{
case 'n': door = DIR_NORTH; break;
case 'e': door = DIR_EAST; break;
case 's': door = DIR_SOUTH; break;
case 'w': door = DIR_WEST; break;
case 'u': door = DIR_UP; break;
case 'd': door = DIR_DOWN; break;
default:
send_to_char( "Please specify directions with a single letter: n|s|e|w|u|d.\n\r", ch );
return;
}
if( location->exit[door] == NULL
|| ( IS_SET( location->exit[door]->exit_info, EX_CLOSED )
&& IS_SET( location->exit[door]->exit_info, EX_NOSHADOW ) ) )
break;
location = location->exit[door]->to_room;
if( get_room_light( location ) > 30 + ch->level / 10 )
{
send_to_char( "The shadows run out and you are revealed.\n\r", ch );
break;
}
}
if( room_is_private( location )
|| location->area->min > level + 50
|| IS_SET( location->area->area_flags, AREA_HIDE )
|| ch->in_room->area->plane != location->area->plane )
{
if( strlen( target ) > 0 )
target[strlen( target ) - 1] = '\0';
else /* the same room...funny, this place is familiar! */
{
destok = TRUE;
location = ch->in_room;
}
}
else
destok = TRUE;
}
while( !destok );
char_from_room( ch );
char_to_room( ch, location );
act( "$n appears from the shadow, where previously there was noone.",
ch, NULL, NULL, TO_ROOM );
do_look( ch, AUTOLOOK );
return;
}
void spell_spiritual_hammer( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *hammer;
AFFECT_DATA *paf;
char buf[MAX_INPUT_LENGTH];
hammer = create_object( get_obj_index( OBJ_VNUM_SPIRIT_HAM ), ch->level );
set_timer_tick( hammer, UMIN( level / 8, 20 ) );
sprintf( buf, hammer->name, ch->name );
free_string( hammer->name );
hammer->name = str_dup( buf );
sprintf( buf, hammer->short_descr, ch->name );
free_string( hammer->short_descr );
hammer->short_descr = str_dup( buf );
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_HITROLL;
paf->modifier = number_fuzzy( ch->level / 4 ) - 1;
vzero( paf->bitvector );
paf->next = hammer->affected;
hammer->affected = paf;
paf = new_affect( );
paf->type = sn;
paf->duration = -1;
paf->location = APPLY_DAMROLL;
paf->modifier = number_fuzzy( ch->level / 5 ) - 2;
vzero( paf->bitvector );
paf->next = hammer->affected;
hammer->affected = paf;
act( "With a bright flash $n summon$% $p, to help $m battle evil.",
ch, hammer, NULL, TO_ALL );
obj_to_char( hammer, ch );
return;
}
void spell_story( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
AFFECT_DATA af;
int sntemp;
if( IS_NPC( ch ) || !ch->in_room )
return;
act( "$n spins a yarn and you all sit down to listen.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You tell a story.\n\r", ch );
af.type = sn;
af.level = level;
af.duration = level / 10;
af.modifier = -7 - level / 50;
vzero( af.bitvector );
sntemp = skill_lookup( "sleep" );
for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if( vch->fighting )
stop_fighting( vch, TRUE );
if( !IS_NPC( ch ) && !IS_NPC( vch ) )
continue;
if( !saves_spell( level, vch, ch, sn ) )
{
act( "$N has been lulled by $n's story.", ch, NULL, vch, TO_NOTVICT );
act( "$N has been lulled by your story.", ch, NULL, vch, TO_CHAR );
act( "You have been lulled by $n's story.", ch, NULL, vch, TO_VICT );
af.location = APPLY_HITROLL;
affect_to_char( vch, &af, NULL );
af.location = APPLY_DAMROLL;
affect_to_char( vch, &af, NULL );
( *skill_table[sntemp].spell_fun )
( sntemp, level - 5, ch, ( void * )vch );
}
}
return;
}
void spell_summon( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim;
if( !( victim = get_char_world( ch, target_name ) )
|| victim == ch
|| !victim->in_room
|| IS_SET( victim->in_room->room_flags, ROOM_SAFE )
|| IS_SET( victim->in_room->room_flags, ROOM_PRIVATE )
|| IS_SET( victim->in_room->room_flags, ROOM_SOLITARY )
|| IS_SET( victim->in_room->room_flags, ROOM_NO_RECALL )
|| IS_SET( victim->in_room->room_flags, ROOM_NO_PORTAL )
|| is_affected( victim, gsn_hex )
|| victim->level >= level + 3
|| victim->fighting
|| ( IS_NPC( victim ) && saves_spell( level, victim, ch, sn ) )
|| victim->in_room->area->plane != ch->in_room->area->plane )
{
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 has summoned you!", ch, NULL, victim, TO_VICT );
act( "$n arrives suddenly.", victim, NULL, NULL, TO_ROOM );
do_look( victim, AUTOLOOK );
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
|| IS_SET( victim->in_room->room_flags, ROOM_NO_RECALL )
|| ( !IS_NPC( ch ) && victim->fighting )
|| ( victim != ch
&& ( saves_spell( level, victim, ch, sn )
|| saves_spell( level, victim, ch, sn ) ) ) )
{
send_to_char( "You failed.\n\r", ch );
return;
}
for( ;; )
{
pRoomIndex = get_room_index( number_range( 0, 65535 ) );
if( pRoomIndex )
if( !IS_SET( pRoomIndex->room_flags, ROOM_PRIVATE )
&& !IS_SET( pRoomIndex->room_flags, ROOM_SOLITARY )
&& !IS_SET( pRoomIndex->room_flags, ROOM_NO_PORTAL )
&& victim->level + 20 >= pRoomIndex->area->min
&& !IS_SET( pRoomIndex->area->area_flags, AREA_HIDE )
&& pRoomIndex->area->plane == victim->in_room->area->plane )
break;
}
if( victim->fighting )
stop_fighting( victim, TRUE );
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, AUTOLOOK );
return;
}
void spell_transport( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *rch;
ROOM_INDEX_DATA *location;
if( target_name[0] == '\0' )
{
send_to_char( "Where did you want to go?\n\r", ch );
return;
}
rch = get_char_world( ch, target_name );
if( !rch || !( location = rch->in_room ) )
{
send_to_char( "Your spell fizzles.\n\r", ch );
return;
}
if( room_is_private( location )
|| IS_SET( location->room_flags, ROOM_NO_PORTAL )
|| location->area->min > level + 50
|| IS_SET( location->area->area_flags, AREA_HIDE )
|| ch->in_room->area->plane == location->area->plane )
{
send_to_char( "Your spell fizzles.\n\r", ch );
return;
}
send_to_char( "You step sideways through a small crack in reality.\n\r",
ch );
act( "$n steps through a small fracture in reality.",
ch, NULL, NULL, TO_ROOM );
char_from_room( ch );
char_to_room( ch, location );
act( "Your skull implodes silently and $n appears.",
ch, NULL, NULL, TO_ROOM );
do_look( ch, AUTOLOOK );
return;
}
void spell_transmute( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
char buf[ MAX_INPUT_LENGTH ];
bool heavier = FALSE;
int chance;
target_name = one_argument( target_name, buf );
if( IS_SET( obj->extra_flags, ITEM_MAGIC ) )
{
send_to_char( "The molecules are bound tightly by a strong force.\n\r", ch );
return;
}
if( !str_cmp( target_name, "heavier" ) )
heavier = TRUE;
else if( str_cmp( target_name, "lighter" ) )
{
send_to_char( "Please specify 'heavier' or 'lighter'.\n\r", ch );
return;
}
chance = obj->pIndexData->material;
chance += ( get_curr_int( ch ) + get_curr_wis( ch ) ) / 2;
if( number_percent() > chance )
{
send_to_char( "The tough material resists your manipulation.\n\r", ch );
return;
}
chance = level / 100 + 2;
obj_from_char( obj );
if( heavier )
obj->weight += chance;
else
obj->weight = UMAX( 0, obj->weight - chance );
SET_BIT( obj->extra_flags, ITEM_MAGIC );
obj_to_char( obj, ch );
act( "$n moulds $p and makes it $T.", ch, obj,
heavier ? "heavier" : "lighter", TO_ROOM );
act( "You mould $p and make it $T.", ch, obj,
heavier ? "heavier" : "lighter", TO_CHAR );
return;
}
void spell_vampiric_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
int chance;
if( IS_NPC( ch ) )
return;
if( obj->item_type != ITEM_WEAPON )
{
send_to_char( "That isn't a weapon.\n\r", ch );
return;
}
chance = level - obj->level + ( ch->pcdata->learned[sn] / 2 );
chance -= number_percent( );
if( chance < -50 )
{
send_to_char( "You fumble and the weapon shatters.\n\r", ch );
extract_obj( obj );
return;
}
if( chance < 0 )
{
send_to_char( "Nothing much happens.\n\r", ch );
return;
}
obj->value[0] = skill_lookup( "energy drain" );
SET_BIT( obj->extra_flags, ITEM_DARK );
act( "$n give$% $p a a never-ending thirst for blood!",
ch, obj, NULL, TO_ALL );
return;
}
void spell_ventriloquate( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char speaker[MAX_INPUT_LENGTH];
target_name = one_argument( target_name, speaker );
sprintf( buf1, "&c%s says '%s&n&c'.&n\n\r",
speaker, target_name );
sprintf( buf2, "&cSomeone makes %s say '%s&n&c'.&n\n\r",
speaker, target_name );
buf1[2] = UPPER( buf1[2] );
for( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if( !is_name( speaker, vch->name ) )
send_to_char( saves_spell( level, vch, ch, sn ) ? buf2 : buf1, vch );
}
return;
}
/*
* This is for muds that want scrolls of recall.
* It also has applications as a means of forcing a recall.
*/
void spell_word_of_recall( int sn, int level, CHAR_DATA *ch, void *vo )
{
do_recall( (CHAR_DATA *)vo, "" );
return;
}