dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// 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;
}

/**************************************************************************/