/**************************************************************************/
// magic_sb.cpp - spells/skills introduced by stormbringer coders
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with the dawn license *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
**************************************************************************/
#include "include.h"
#include "magic.h"
/**************************************************************************/
// From Secret Destroyer MUD by Luke.
// Added by Meerclar 03-17-2002 for SB:R
SPRESULT spell_vicegrip(int sn, int level, char_data *ch, void *vo, int target)
{
char_data *victim = (char_data *) vo;
AFFECT_DATA af;
if (victim != ch)
{
ch->println("You may only cast this on yourself.");
return HALF_MANA;
}
if (IS_AFFECTED2(victim, sn)){
if (victim == ch){
ch->println("You already have a vicegrip on your weapon.");
}
return HALF_MANA;
}
af.where = WHERE_AFFECTS2;
af.type = sn;
af.level = level;
af.duration = 20;
af.location = APPLY_AC;
af.modifier = -5;
af.bitvector= AFF2_VICEGRIP;
affect_to_char(victim, &af);
act("$n's hands grip their weapon with an iron hold.",victim, NULL,NULL, TO_ROOM);
act("You hold on to your weapon with all your might.",victim, NULL,NULL, TO_CHAR);
return FULL_MANA;
}
/***************************************************************************/
SPRESULT spell_sb_gate( int sn, int level, char_data *ch, void *vo,int )
{
char_data *victim = (char_data *) vo;
OBJ_DATA *gatec;
OBJ_DATA *gatev;
// bool gate_pet;
if (( victim = get_char_icworld( ch, target_name ) ) == NULL
|| victim == ch
|| victim->in_room == NULL
|| !can_see_room(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_NOSCRY)
|| IS_SET(victim->in_room->room_flags, ROOM_ANTIMAGIC)
|| IS_SET(victim->in_room->area->area_flags, AREA_NOSCRY)
|| IS_SET(victim->in_room->area->area_flags, AREA_NOGATEINTO)
|| IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
|| victim->level >= level + 3
|| (!IS_NPC(victim) && victim->level >= LEVEL_IMMORTAL) // NOT trust
|| (IS_NPC(victim) && IS_SET(victim->imm_flags,IMM_SUMMON))
|| (IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)))
|| (!IS_NPC(victim) && saves_spell( level, victim, DAMTYPE(sn))))
{
ch->println("A shimmering gateway appears, but seems unstable");
act("A shimmering gateway swirls into existance.",ch,NULL,NULL,TO_ROOM);
gatec = create_object( get_obj_index(OBJ_VNUM_PORTAL)); //Needs a new OBJ_VNUM_GATE
gatec->timer = 10;
obj_to_room(gatec, ch->in_room);
SET_BIT(gatec->value[2],GATE_OPAQUE);
return FULL_MANA;
}else{
if ( ch->in_room->area->continent != victim->in_room->area->continent ){
ch->println( "The spell cannot span such a great distance." );
return FULL_MANA;
}
ch->println("A shimmering gateway swirls into existance.");
act("A shimmering gateway swirls into exastance.", ch,NULL,NULL,TO_ROOM);
victim->printf("A shimmering gateway swirls into existance.");
act("A shimmering gateway swirls into existance.",victim,NULL,NULL,TO_ROOM);
gatec = create_object(get_obj_index(OBJ_VNUM_PORTAL));
gatev = create_object(get_obj_index(OBJ_VNUM_PORTAL));
SET_BIT(gatec->value[2],GATE_SHORT_LOOKINTO);
SET_BIT(gatev->value[2],GATE_SHORT_LOOKINTO);
gatec->value[3] = victim->in_room->vnum;
gatev->value[3] = ch->in_room->vnum;
gatec->timer = 10;
gatev->timer = 10;
obj_to_room( gatec, ch->in_room);
obj_to_room( gatev, victim->in_room);
return FULL_MANA;
}
}
/**************************************************************************/
SPRESULT spell_sb_portal( int sn, int level, char_data *ch, void *,int )
{
char_data *victim;
OBJ_DATA *portal;
if ((victim = get_char_world( ch, target_name ) ) == NULL
|| victim == ch
|| victim->in_room == NULL
|| !can_see_room(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_ANTIMAGIC)
|| IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
|| IS_SET(victim->in_room->area->area_flags, AREA_NOPORTALINTO)
|| IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
|| victim->level >= level + 3
|| (!IS_NPC(victim) && victim->level >= LEVEL_HERO) /* NOT trust */
|| (IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)) )
|| (is_clan(victim) && !is_same_clan(ch,victim)))
{
ch->printf( "A glowing portal appears, but seems unstable.\r\n" );
act("A glowing portal appears, but seems unstable.",ch,NULL,NULL,TO_ROOM);
portal = create_object( get_obj_index ( OBJ_VNUM_PORTAL ));
portal->timer = 6;
obj_to_room( portal, ch->in_room);
SET_BIT(portal->value[2],GATE_OPAQUE);
return FULL_MANA;
}else{
portal = create_object(get_obj_index(OBJ_VNUM_PORTAL));
portal->timer = 2 + level / 25;
portal->value[3] = victim->in_room->vnum;
// portals aren't opaque - Kal August 98
// SET_BIT(portal->value[2],GATE_OPAQUE);
// Now we can see into stable portals - Balo - 07-12-01
SET_BIT(portal->value[2],GATE_SHORT_LOOKINTO);
obj_to_room(portal,ch->in_room);
act("$p rises up from the ground.",ch,portal,NULL,TO_ROOM);
ch->printf( "A glowing portal appears.\r\n" );
//act("$p rises up before you.",ch,portal,NULL,TO_CHAR);
return FULL_MANA;
}
}
/**************************************************************************/
//Changed from orig blindness func by Meerclar 24Oct2002
SPRESULT spell_sb_blindness( int sn, int level, char_data *ch, void *vo, int )
{
char_data *victim = (char_data *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_BLIND))
{
ch->printlnf( "%s already appears to be blinded.", PERS(victim, ch));
return HALF_MANA;
}
if (saves_spell(level,victim,DAMTYPE(sn)))
{
ch->printlnf( "%s seems unaffected.", PERS(victim, ch) );
return FULL_MANA;
}
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.location = APPLY_HITROLL;
af.modifier = -40; //Orig value -4
af.duration = 1+level;
af.bitvector = AFF_BLIND;
affect_to_char( victim, &af );
victim->println( "You are blinded!" );
act("$n appears to be blinded.",victim,NULL,NULL,TO_ROOM);
return FULL_MANA;
}
/**************************************************************************/
// Changed by Meerclar, 24Oct2002 - changes noted inline
// RT calm spell stops all fighting in the room
SPRESULT spell_sb_calm( int sn, int level, char_data *ch, void *,int )
{
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_NPC( vch )
&& ( IS_SET( vch->imm_flags, IMM_MAGIC )
|| IS_SET( vch->act, ACT_UNDEAD )))
return FULL_MANA;
if ( IS_AFFECTED( vch, AFF_CALM )
|| IS_AFFECTED( vch, AFF_BERSERK )
|| is_affected( vch, gsn_frenzy ))
return FULL_MANA;
vch->println( "A wave of calm passes over you." );
if (vch->fighting || vch->position == POS_FIGHTING )
stop_fighting( vch, false );
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.duration = level/4;
af.location = APPLY_HITROLL;
if (!IS_NPC(vch))
af.modifier = -50; //Changed from orig -5 value
else
af.modifier = -20; //Changed from orig -2 value
af.bitvector = AFF_CALM;
affect_to_char(vch,&af);
af.location = APPLY_DAMROLL;
affect_to_char(vch,&af);
}
}
return FULL_MANA;
}
/**************************************************************************/
// Changed to useful healing levels by Meerclar 24Oct2002
SPRESULT spell_sb_cure_critical( int , int level, char_data *ch, void *vo,int )
{
char_data *victim = (char_data *) vo;
int heal = dice(3,8)+level-6;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
victim->println( "You feel better!" );
if ( ch != victim ){
ch->println( "Ok." );
}
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_cure_light( int , int level, char_data *ch, void *vo,int )
{
char_data *victim = (char_data *) vo;
int heal = dice(1, 8)+level/3;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
victim->println( "You feel better!" );
if ( ch != victim ){
ch->println( "Ok." );
}
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_cure_serious( int , int level, char_data *ch, void *vo,int )
{
char_data *victim = (char_data *) vo;
int heal = dice(2, 8)+level/2;
victim->hit = UMIN( victim->hit + heal, victim->max_hit );
update_pos( victim );
victim->println( "You feel better!" );
if ( ch != victim ){
ch->println( "Ok." );
}
return FULL_MANA;
}
/**************************************************************************/
// RT really nasty high-level attack spell
// movement and hp costs to caster reduced to make cleric types more attractive
SPRESULT spell_sb_holy_word(int sn, int level, char_data *ch, void *,int )
{
char_data *vch;
char_data *vch_next;
int dam;
int bless_num, curse_num, frenzy_num;
bless_num = gsn_bless;
curse_num = gsn_curse;
frenzy_num = gsn_frenzy;
act("$n utters a word of divine power!",ch,NULL,NULL,TO_ROOM);
ch->printf( "You utter a word of divine power.\r\n" );
for ( vch = ch->in_room->people; vch != NULL; vch = vch_next )
{
vch_next = vch->next_in_room;
if ((IS_GOOD(ch) && IS_GOOD(vch))
|| (IS_EVIL(ch) && IS_EVIL(vch))
|| (IS_NEUTRAL(ch) && IS_NEUTRAL(vch)))
{
vch->printf( "You feel full more powerful.\r\n" );
spell_frenzy(frenzy_num,level,ch,(void *) vch,TARGET_CHAR);
spell_bless(bless_num,level,ch,(void *) vch,TARGET_CHAR);
}
else if ((IS_GOOD(ch) && IS_EVIL(vch))
|| (IS_EVIL(ch) && IS_GOOD(vch)))
{
if (!is_safe_spell(ch,vch,true))
{
spell_curse(curse_num,level,ch,(void *) vch,TARGET_CHAR);
vch->printf( "You are struck down!\r\n" );
dam = dice(level,12);
damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
}
}
else if (IS_NEUTRAL(vch))
{
if (!is_safe_spell(ch,vch,true))
{
spell_curse(curse_num,level/2,ch,(void *) vch,TARGET_CHAR);
vch->printf( "You are struck down!\r\n" );
dam = dice(level,10);
damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
}
}
}
ch->printf( "You feel drained.\r\n" );
ch->move /= 2;
ch->hit *= 3/4;
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_protection_evil(int sn,int level,char_data *ch,void *vo, int )
{
char_data *victim = (char_data *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_PROTECT_EVIL)
|| IS_AFFECTED(victim, AFF_PROTECT_GOOD))
{
if (victim == ch)
ch->printf( "You are already protected.\r\n" );
else
act("$N is already protected.",ch,NULL,victim,TO_CHAR);
return HALF_MANA;
}
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.duration = 24;
af.location = APPLY_SAVES;
af.modifier = -1 * level/8;
af.bitvector = AFF_PROTECT_EVIL;
affect_to_char( victim, &af );
victim->printf( "You feel holy and pure.\r\n" );
if ( ch != victim )
act("$N is protected from evil.",ch,NULL,victim,TO_CHAR);
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_protection_good(int sn,int level,char_data *ch,void *vo,int )
{
char_data *victim = (char_data *) vo;
AFFECT_DATA af;
if ( IS_AFFECTED(victim, AFF_PROTECT_GOOD)
|| IS_AFFECTED(victim, AFF_PROTECT_EVIL))
{
if (victim == ch)
ch->printf( "You are already protected.\r\n" );
else
act("$N is already protected.",ch,NULL,victim,TO_CHAR);
return HALF_MANA;
}
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.duration = 24;
af.location = APPLY_SAVES;
af.modifier = -1 * level/8;
af.bitvector = AFF_PROTECT_GOOD;
affect_to_char( victim, &af );
victim->printf( "You feel aligned with darkness.\r\n" );
if ( ch != victim )
act("$N is protected from good.",ch,NULL,victim,TO_CHAR);
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_word_of_recall( int, int, char_data *ch,void *vo,int )
{
char_data *victim = (char_data *) vo;
ROOM_INDEX_DATA *location = NULL;
if(IS_NPC(victim)){
return NO_MANA;
}
// class recall spot first, then race
// recall_vnum = pc_race_table[ch->race].recall_room;
if ( class_table[victim->clss].recall)
{
location = get_room_index( class_table[victim->clss].recall ); // Class
}
else // Class recall room non-existant, check race room
{
location = get_room_index( race_table[victim->race]->recall_room); // Race
}
if ( location == NULL )
{
victim->println( "You are completely lost." );
return NO_MANA;
}
if (IS_SET(victim->in_room->room_flags,ROOM_NO_RECALL)
|| IS_SET(victim->in_room->room_flags, ROOM_ANTIMAGIC)
|| IS_AFFECTED(victim,AFF_CURSE))
{
victim->println( "Spell failed." );
return FULL_MANA;
}
if (victim->fighting != NULL)
stop_fighting(victim,true);
// Stop negative moves characters from defrauding the system
if (ch->move>0 && IS_IC(ch))
ch->move /= 3*4;
act("$n disappears.",victim,NULL,NULL,TO_ROOM);
char_from_room(victim);
char_to_room(victim,location);
act("$n appears in the room.",victim,NULL,NULL,TO_ROOM);
do_look(victim,"auto");
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_strength_of_the_land( int sn, int level, char_data *ch, void *, int )
{
AFFECT_DATA af;
if ( is_affected( ch, gsn_illusions_grandeur )) {
ch->printf( "Spell failed.\r\n" );
return HALF_MANA;
}
//Switch to check sectors
switch ( ch->in_room->sector_type ) {
case SECT_INSIDE:
case SECT_CITY:
ch->printf( "You're too far from Nature to summon the strength.\r\n" );
return HALF_MANA;
break;
case SECT_AIR:
ch->printf( "You try to summon the land's strength, but are too high in the air.\r\n" );
return HALF_MANA;
break;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
ch->printf( "You try to summon the land's strength, but are too far from land itself.\r\n" );
return HALF_MANA;
break;
case SECT_UNDERWATER:
ch->printf( "You try to summon the land's strength, but are too deep underwater to do so.\r\n" );
return HALF_MANA;
break;
// Always happens if not in the above sectors :)
// default: //Should never happen.
// return HALF_MANA;
// break;
}
if ( !is_affected(ch,sn) )
{
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.duration = level/8;
af.location = APPLY_HIT;
af.modifier = level*2;
af.bitvector = 0;
affect_to_char( ch, &af );
af.location = APPLY_AC;
af.modifier = level/8;
af.bitvector = 0;
affect_to_char( ch, &af );
af.location = APPLY_SAVES;
af.modifier = level/8;
af.bitvector = 0;
affect_to_char( ch, &af );
ch->printf( "The power of the land enriches you!\r\n" );
act( "$n glows bright green for a moment.\r\n", ch, NULL, NULL, TO_ROOM );
}
else
{
ch->printf( "You are already enriched with the power of the land.\r\n" );
return HALF_MANA;
}
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_magic_missile( int sn, int level, char_data *ch,void *vo,int )
{
char_data *victim = (char_data *) vo;
int dam;
int num_missile;
//start missile strikes
num_missile = level/10 + 1;
dam = dice(level/4,5);
if ( saves_spell( level, victim,DAMTYPE(sn)) )
dam /= 2;
damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
num_missile -= 1;
while (num_missile > 0){
dam = dice(level/4,5);
if ( saves_spell( level, victim,DAMTYPE(sn)) )
dam /= 2;
damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
num_missile -= 1;
}
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_illusions_grandeur( int sn, int level, char_data *ch, void *vo, int )
{
char_data *victim = (char_data *) vo;
AFFECT_DATA af;
if ( is_affected( victim, gsn_strength_of_the_land )) {
ch->println("Spell failed.");
return HALF_MANA;
}
if(!is_affected(victim,sn))
{
af.where = WHERE_AFFECTS;
af.type = sn;
af.level = level;
af.duration = level/10;
af.location = APPLY_HIT;
af.modifier = level;
af.bitvector = 0;
affect_to_char( victim, &af );
af.location = APPLY_AC;
af.modifier = level/8;
af.bitvector = 0;
affect_to_char( ch, &af );
af.location = APPLY_SAVES;
af.modifier = level/8;
af.bitvector = 0;
affect_to_char( ch, &af );
victim->println("You appear mightier than you are!");
act( "$n grows in stature and appears quite mighty now!", victim, NULL, NULL, TO_ROOM );
}
else
{
victim->println("You are having delusions of grandeur now.");
return HALF_MANA;
}
return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_sb_poison_rain( int sn, int level, char_data *ch, void *, int )
{
char_data *vch;
char_data *vch_next;
int dam;
AFFECT_DATA af;
if ( !IS_OUTSIDE( ch ) )
{
ch->println("You must be out of doors.");
return NO_MANA;
}
if ( ch->in_room->sector_type == SECT_CAVE )
{
ch->println("You can't make it rain here.");
return NO_MANA;
}
dam = dice( level , 8 );
af.where = WHERE_AFFECTS;
af.type = gsn_poison;
af.level = level;
af.duration = level;
af.location = APPLY_ST;
af.modifier = -20;
af.bitvector = AFF_POISON;
ch->println("A burning rain falls on your enemy's heads!");
act( "$n brings forth a rain of poison!", ch, NULL, NULL, TO_ROOM );
for ( vch = ch->in_room->people; vch; vch = vch_next )
{
vch_next=vch->next_in_room;
// dont affect unseen mobs
if ( IS_NPC(vch) && IS_SET(vch->act, ACT_IS_UNSEEN)){
continue;
}
if (vch->in_room == NULL)
continue;
if ( vch->in_room == ch->in_room )
{
if ( vch != ch
&& ( IS_NPC( ch ) ? !IS_NPC( vch ) : IS_NPC( vch ) )
&& !HAS_CLASSFLAG(vch, CLASSFLAG_POISON_IMMUNITY))
{
damage_spell( ch, vch, saves_spell( level, vch, DAMTYPE(sn) ) ? dam /2 : dam, sn, DAMTYPE(sn), true );
if(!saves_spell(level,vch, DAMTYPE(sn)))
affect_join( vch, &af );
}
continue;
}
}
return FULL_MANA;
}
/**************************************************************************/