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